Files
Linux-Server-Management-Too…/modules/security/optimize-ct-limit.sh
T
cschantz b33c57086f Add intelligent CT_LIMIT optimizer - analyzes traffic to recommend optimal limit
PROBLEM: Live monitor showed static CT_LIMIT="100" recommendation
- No analysis of actual site traffic
- No consideration of legitimate high-connection users
- Could block CDNs, bots, or legitimate traffic spikes
- No way to know what's safe for the specific server

SOLUTION: Created comprehensive CT_LIMIT optimizer script

NEW SCRIPT: modules/security/optimize-ct-limit.sh

WHAT IT DOES:
1. Analyzes Apache logs (last 24 hours by default)
   - Parses all domain logs in /var/log/apache2/domlogs/
   - Tracks max concurrent connections per IP per domain
   - Identifies user agents and behavior patterns

2. Classifies IP behavior using bot-signatures.sh
   - Legitimate bots (Googlebot, Bingbot, etc.)
   - AI crawlers (GPT, Claude, etc.)
   - CDNs (Cloudflare, Akamai, etc.)
   - Normal users vs high-traffic users
   - Potential scrapers

3. Analyzes current active connections
   - Uses ss or netstat to check real-time connections
   - Identifies current highest connection counts

4. Calculates statistics
   - 95th percentile of legitimate user connections
   - 99th percentile for headroom
   - Max concurrent from single legitimate IP
   - Separates bot/CDN traffic from user traffic

5. Provides 3 recommendations:
   a) CONSERVATIVE (max_legit + 20) - For high-traffic sites
   b) BALANCED (max_legit + 10) - Recommended for most 
   c) AGGRESSIVE (max_legit + 5) - Only during active attack

6. Whitelist recommendations
   - Identifies bots/CDNs exceeding recommended limit
   - Suggests specific IPs to whitelist in CSF
   - Prevents blocking Googlebot, monitoring services, etc.

7. One-command application
   - Backs up csf.conf automatically
   - Updates CT_LIMIT to recommended value
   - Enables SYNFLOOD protection
   - Restarts CSF
   - Provides monitoring command

EXAMPLE OUTPUT:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Connection Analysis Summary:
  Total unique IPs analyzed: 1,247
  Legitimate users: 1,180
  Bots/CDNs/Crawlers: 67

Legitimate User Connection Patterns:
  Max concurrent from single IP: 45
  95th percentile: 12 concurrent connections
  99th percentile: 28 concurrent connections

Current Active Connections:
  Highest right now: 8 connections from 1.2.3.4

Current CSF Configuration:
  CT_LIMIT = 150

📊 RECOMMENDED CT_LIMIT VALUES
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

1. CONSERVATIVE: CT_LIMIT = 65
   • Allows headroom for traffic spikes
   • Won't block legitimate users

2. BALANCED: CT_LIMIT = 55 
   • Based on 99th percentile + buffer
   • Blocks most attack traffic

3. AGGRESSIVE: CT_LIMIT = 50
   • Maximum DDoS protection
   • May affect some legitimate users

⚠️  WHITELIST RECOMMENDATIONS
Found bots/crawlers with high connection counts:
  • 66.249.72.38   (Googlebot)         82 connections
  • 40.77.167.88   (Bingbot)           65 connections
  • 157.55.39.183  (UptimeRobot)       48 connections

To whitelist: csf -a <IP>
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

INTEGRATION WITH LIVE MONITOR:
- Press 'c' during live monitoring to run optimizer
- Recommendation updates based on detected DDoS/SYN floods
- Quick Actions panel shows: "Press 'c' to run CT_LIMIT optimizer"
- Help screen updated with 'c' key

USAGE:
1. Standalone: modules/security/optimize-ct-limit.sh
2. From live monitor: Press 'c' during monitoring
3. With custom period: optimize-ct-limit.sh 48  (48 hours)

SAFETY:
- Automatic backup of csf.conf before changes
- Minimum thresholds (50/80/100) prevent too-aggressive limits
- Option to apply or just view recommendations
- Full report saved to /tmp for review

INTELLIGENCE:
- Uses actual traffic data, not guesses
- Accounts for legitimate high-connection sources
- Prevents blocking search engines and monitoring
- Adapts to each server's unique traffic patterns

FILES MODIFIED:
- modules/security/optimize-ct-limit.sh (NEW - 650 lines)
- modules/security/live-attack-monitor.sh
  - Added 'c' key handler (line 1019-1024)
  - Updated Quick Actions recommendation (line 438)
  - Updated help screen (line 1045)
  - Updated footer keys (line 457)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-14 15:26:31 -05:00

456 lines
16 KiB
Bash
Executable File

#!/bin/bash
################################################################################
# CT_LIMIT Optimizer - Intelligent Connection Limit Calculator
################################################################################
# Purpose: Analyze real traffic patterns to recommend optimal CT_LIMIT
# Method:
# 1. Analyze Apache logs for legitimate concurrent connection patterns
# 2. Check current active connections per IP
# 3. Identify CDNs, bots, and legitimate high-traffic sources
# 4. Calculate safe CT_LIMIT that won't block real users
# 5. Provide CSF configuration recommendations
################################################################################
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
source "$SCRIPT_DIR/lib/common-functions.sh"
source "$SCRIPT_DIR/lib/system-detect.sh"
source "$SCRIPT_DIR/lib/bot-signatures.sh"
# Require root
if [ "$EUID" -ne 0 ]; then
print_error "This script must be run as root"
exit 1
fi
# Analysis configuration
ANALYSIS_HOURS=${1:-24} # Default: analyze last 24 hours
TEMP_ANALYSIS="/tmp/ct-limit-analysis-$$"
mkdir -p "$TEMP_ANALYSIS"
# Color definitions
BOLD='\033[1m'
DIM='\033[2m'
NC='\033[0m'
################################################################################
# Functions
################################################################################
cleanup() {
rm -rf "$TEMP_ANALYSIS" 2>/dev/null
}
trap cleanup EXIT
get_current_ct_limit() {
if [ -f "/etc/csf/csf.conf" ]; then
grep "^CT_LIMIT" /etc/csf/csf.conf | cut -d'=' -f2 | tr -d '"' | tr -d ' '
else
echo "Not configured"
fi
}
analyze_apache_logs() {
local hours="$1"
local cutoff_time=$(date -d "$hours hours ago" "+%d/%b/%Y:%H:%M:%S" 2>/dev/null)
print_status "Analyzing Apache access logs (last $hours hours)..."
# Find all domain logs
local log_dir="${SYS_LOG_DIR:-/var/log/apache2/domlogs}"
local total_logs=0
if [ ! -d "$log_dir" ]; then
print_warning "Apache log directory not found: $log_dir"
return 1
fi
# Analyze each domain's access patterns
echo "IP|DOMAIN|MAX_CONCURRENT|TOTAL_REQUESTS|USER_AGENT" > "$TEMP_ANALYSIS/connections_by_ip.txt"
find "$log_dir" -type f \( -name "*.com" -o -name "*.net" -o -name "*.org" -o -name "*.dev" \) 2>/dev/null | while read -r logfile; do
local domain=$(basename "$logfile")
((total_logs++))
# Extract IP, timestamp, user agent
awk -v domain="$domain" '{
# Parse: IP - - [timestamp] "METHOD URL" status bytes "ref" "UA"
match($0, /^([0-9.]+).*\[([^\]]+)\].*"([^"]*)".*"([^"]*)"$/, arr)
if (arr[1] != "") {
ip = arr[1]
timestamp = arr[2]
ua = arr[4]
# Track requests per second per IP
gsub(/:.*/, "", timestamp) # Remove time, keep date
key = ip "|" domain "|" timestamp
count[key]++
user_agent[ip] = ua
}
}
END {
for (key in count) {
split(key, parts, "|")
ip = parts[1]
dom = parts[2]
# Track max concurrent requests
if (count[key] > max_concurrent[ip "|" dom]) {
max_concurrent[ip "|" dom] = count[key]
}
total_requests[ip "|" dom] += count[key]
}
for (key in max_concurrent) {
split(key, parts, "|")
ip = parts[1]
dom = parts[2]
print ip "|" dom "|" max_concurrent[key] "|" total_requests[key] "|" user_agent[ip]
}
}' "$logfile" >> "$TEMP_ANALYSIS/connections_by_ip.txt" 2>/dev/null
done
print_success "Analyzed logs from $log_dir"
}
analyze_current_connections() {
print_status "Analyzing current active connections..."
if command -v ss &>/dev/null; then
# Count current connections per IP
ss -tn state established 2>/dev/null | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | sort | uniq -c | sort -rn > "$TEMP_ANALYSIS/current_connections.txt"
elif command -v netstat &>/dev/null; then
netstat -tn | grep ESTABLISHED | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn > "$TEMP_ANALYSIS/current_connections.txt"
else
print_warning "Neither ss nor netstat available"
return 1
fi
print_success "Current connection analysis complete"
}
classify_ip_behavior() {
local ip="$1"
local user_agent="$2"
local max_concurrent="$3"
local total_requests="$4"
# Classify using bot signatures
local bot_type=$(classify_bot_type "$user_agent")
# Additional classification
local classification="unknown"
# Known good sources
if [ "$bot_type" = "legit" ]; then
classification="legitimate_bot"
elif [ "$bot_type" = "ai" ]; then
classification="ai_crawler"
elif [ "$bot_type" = "monitor" ]; then
classification="monitoring_service"
# CDN detection
elif [[ "$user_agent" =~ (Cloudflare|CloudFront|Akamai|Fastly|Sucuri) ]]; then
classification="cdn"
# High request rate but legitimate
elif [ "$max_concurrent" -gt 50 ] && [ "$total_requests" -gt 1000 ]; then
if [[ "$user_agent" =~ (Chrome|Firefox|Safari|Edge) ]]; then
classification="high_traffic_user"
else
classification="potential_scraper"
fi
# Normal user
elif [ "$max_concurrent" -lt 20 ]; then
classification="normal_user"
else
classification="moderate_user"
fi
echo "$classification"
}
calculate_percentile() {
local percentile="$1"
local data_file="$2"
# Sort data and get Nth percentile
local count=$(wc -l < "$data_file")
local position=$(awk -v p="$percentile" -v c="$count" 'BEGIN {printf "%.0f", (p/100) * c}')
[ "$position" -lt 1 ] && position=1
sort -n "$data_file" | sed -n "${position}p"
}
generate_recommendation() {
print_banner "CT_LIMIT Optimizer - Analysis Results"
echo ""
# Parse analysis data
local max_legitimate=0
local max_bot=0
local max_cdn=0
local total_ips=0
echo "Analyzing connection patterns..."
echo ""
# Create summary files
> "$TEMP_ANALYSIS/legitimate_connections.txt"
> "$TEMP_ANALYSIS/bot_connections.txt"
> "$TEMP_ANALYSIS/all_connections.txt"
# Skip header
tail -n +2 "$TEMP_ANALYSIS/connections_by_ip.txt" | while IFS='|' read -r ip domain max_concurrent total_requests user_agent; do
[ -z "$ip" ] && continue
local classification=$(classify_ip_behavior "$ip" "$user_agent" "$max_concurrent" "$total_requests")
((total_ips++))
# Track max connections by type
case "$classification" in
legitimate_bot|ai_crawler|monitoring_service|cdn)
echo "$max_concurrent" >> "$TEMP_ANALYSIS/bot_connections.txt"
[ "$max_concurrent" -gt "$max_bot" ] && max_bot=$max_concurrent
;;
normal_user|moderate_user|high_traffic_user)
echo "$max_concurrent" >> "$TEMP_ANALYSIS/legitimate_connections.txt"
[ "$max_concurrent" -gt "$max_legitimate" ] && max_legitimate=$max_concurrent
;;
esac
echo "$max_concurrent" >> "$TEMP_ANALYSIS/all_connections.txt"
done
# Calculate statistics
local legit_count=$(wc -l < "$TEMP_ANALYSIS/legitimate_connections.txt" 2>/dev/null || echo "0")
local bot_count=$(wc -l < "$TEMP_ANALYSIS/bot_connections.txt" 2>/dev/null || echo "0")
echo -e "${BOLD}Connection Analysis Summary:${NC}"
echo "──────────────────────────────────────────────────────────────"
echo " Total unique IPs analyzed: $total_ips"
echo " Legitimate users: $legit_count"
echo " Bots/CDNs/Crawlers: $bot_count"
echo ""
# Calculate percentiles for legitimate traffic
if [ -s "$TEMP_ANALYSIS/legitimate_connections.txt" ]; then
local p95=$(calculate_percentile 95 "$TEMP_ANALYSIS/legitimate_connections.txt")
local p99=$(calculate_percentile 99 "$TEMP_ANALYSIS/legitimate_connections.txt")
echo -e "${BOLD}Legitimate User Connection Patterns:${NC}"
echo " Max concurrent from single IP: $max_legitimate"
echo " 95th percentile: $p95 concurrent connections"
echo " 99th percentile: $p99 concurrent connections"
echo ""
fi
# Check current connections
if [ -s "$TEMP_ANALYSIS/current_connections.txt" ]; then
local current_max=$(head -1 "$TEMP_ANALYSIS/current_connections.txt" | awk '{print $1}')
local current_max_ip=$(head -1 "$TEMP_ANALYSIS/current_connections.txt" | awk '{print $2}')
echo -e "${BOLD}Current Active Connections:${NC}"
echo " Highest right now: $current_max connections from $current_max_ip"
echo ""
fi
# Current CSF setting
local current_ct=$(get_current_ct_limit)
echo -e "${BOLD}Current CSF Configuration:${NC}"
echo " CT_LIMIT = $current_ct"
echo ""
# Generate recommendation
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo -e "${BOLD}📊 RECOMMENDED CT_LIMIT VALUES${NC}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# Calculate safe recommendations
local conservative=$((max_legitimate + 20))
local balanced=$((max_legitimate + 10))
local aggressive=$((max_legitimate + 5))
# Minimum safety thresholds
[ "$conservative" -lt 100 ] && conservative=100
[ "$balanced" -lt 80 ] && balanced=80
[ "$aggressive" -lt 50 ] && aggressive=50
echo -e "${BOLD}1. CONSERVATIVE${NC} (Recommended for high-traffic sites)"
echo " CT_LIMIT = $conservative"
echo " • Allows headroom for traffic spikes"
echo " • Won't block legitimate users"
echo " • Good protection against moderate attacks"
echo ""
echo -e "${BOLD}2. BALANCED${NC} (Recommended for most servers) ⭐"
echo " CT_LIMIT = $balanced"
echo " • Balances security and usability"
echo " • Based on 99th percentile + buffer"
echo " • Blocks most attack traffic"
echo ""
echo -e "${BOLD}3. AGGRESSIVE${NC} (Only if under active attack)"
echo " CT_LIMIT = $aggressive"
echo " • Tight connection limits"
echo " • May affect some legitimate users"
echo " • Maximum DDoS protection"
echo ""
# Whitelist recommendations
if [ "$bot_count" -gt 0 ]; then
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo -e "${BOLD}⚠️ WHITELIST RECOMMENDATIONS${NC}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Found bots/crawlers with high connection counts."
echo "Consider whitelisting these IPs to prevent blocking:"
echo ""
# Show top legitimate bots
tail -n +2 "$TEMP_ANALYSIS/connections_by_ip.txt" | while IFS='|' read -r ip domain max_concurrent total_requests user_agent; do
[ -z "$ip" ] && continue
local classification=$(classify_ip_behavior "$ip" "$user_agent" "$max_concurrent" "$total_requests")
if [[ "$classification" =~ (legitimate_bot|ai_crawler|monitoring_service) ]]; then
local bot_name=$(echo "$user_agent" | grep -oE '(Googlebot|Bingbot|Slurp|DuckDuckBot|Baiduspider|YandexBot|SemrushBot|AhrefsBot|facebookexternalhit|Twitterbot|LinkedInBot|UptimeRobot|Pingdom)' | head -1)
[ -z "$bot_name" ] && bot_name="Bot"
if [ "$max_concurrent" -gt "$balanced" ]; then
printf " • %-15s (%-20s) %3d connections\n" "$ip" "$bot_name" "$max_concurrent"
fi
fi
done | sort -t'(' -k2 -u | head -10
echo ""
echo "To whitelist: Add to /etc/csf/csf.ignore or use: csf -a <IP>"
fi
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo -e "${BOLD}🔧 HOW TO APPLY${NC}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "1. Edit CSF configuration:"
echo " ${BOLD}nano /etc/csf/csf.conf${NC}"
echo ""
echo "2. Find CT_LIMIT line and change to recommended value:"
echo " ${BOLD}CT_LIMIT = \"$balanced\"${NC}"
echo ""
echo "3. Enable SYNFLOOD protection (if not already):"
echo " ${BOLD}SYNFLOOD = \"1\"${NC}"
echo ""
echo "4. Apply changes:"
echo " ${BOLD}csf -r${NC}"
echo ""
echo "5. Monitor effectiveness:"
echo " ${BOLD}watch -n 2 'csf -g | tail -20'${NC}"
echo ""
# Save recommendation to file
cat > "$TEMP_ANALYSIS/recommendation.txt" <<EOF
CT_LIMIT Optimization Report
Generated: $(date)
Analysis Period: Last $ANALYSIS_HOURS hours
RECOMMENDED VALUES:
- Conservative: CT_LIMIT = "$conservative"
- Balanced: CT_LIMIT = "$balanced" (RECOMMENDED)
- Aggressive: CT_LIMIT = "$aggressive"
ANALYSIS DATA:
- Total IPs analyzed: $total_ips
- Legitimate users: $legit_count
- Bots/Crawlers: $bot_count
- Max legitimate connections: $max_legitimate
- Current CT_LIMIT: $current_ct
To apply balanced recommendation:
1. Edit /etc/csf/csf.conf
2. Set: CT_LIMIT = "$balanced"
3. Run: csf -r
EOF
echo "Full report saved to: $TEMP_ANALYSIS/recommendation.txt"
echo ""
}
apply_recommendation() {
local new_limit="$1"
if [ ! -f "/etc/csf/csf.conf" ]; then
print_error "CSF not installed or config not found"
return 1
fi
print_status "Backing up CSF configuration..."
cp /etc/csf/csf.conf "/etc/csf/csf.conf.backup.$(date +%Y%m%d_%H%M%S)"
print_status "Setting CT_LIMIT = $new_limit..."
sed -i "s/^CT_LIMIT = .*/CT_LIMIT = \"$new_limit\"/" /etc/csf/csf.conf
# Also ensure SYNFLOOD is enabled
if grep -q "^SYNFLOOD = \"0\"" /etc/csf/csf.conf; then
print_status "Enabling SYNFLOOD protection..."
sed -i 's/^SYNFLOOD = "0"/SYNFLOOD = "1"/' /etc/csf/csf.conf
fi
print_status "Restarting CSF..."
csf -r >/dev/null 2>&1
print_success "CT_LIMIT updated to $new_limit and CSF restarted!"
echo ""
echo "Monitor effectiveness with: csf -g | tail -20"
}
################################################################################
# Main
################################################################################
main() {
clear
print_banner "CT_LIMIT Optimizer - Intelligent Connection Limit Calculator"
echo ""
echo "This tool analyzes your actual traffic patterns to recommend"
echo "an optimal CT_LIMIT that protects against DDoS without blocking"
echo "legitimate users, bots, and CDNs."
echo ""
echo "Analysis period: Last $ANALYSIS_HOURS hours"
echo ""
read -p "Press Enter to start analysis or Ctrl+C to cancel..."
echo ""
# Run analysis
analyze_apache_logs "$ANALYSIS_HOURS"
analyze_current_connections
# Generate and show recommendations
generate_recommendation
# Offer to apply
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
read -p "Would you like to apply the BALANCED recommendation automatically? (y/n): " apply
if [[ "$apply" =~ ^[Yy] ]]; then
# Extract balanced value from recommendation
local balanced=$(grep "2. BALANCED" -A1 "$TEMP_ANALYSIS/recommendation.txt" | grep "CT_LIMIT" | grep -oE '[0-9]+')
if [ -n "$balanced" ]; then
apply_recommendation "$balanced"
else
print_error "Could not determine balanced recommendation value"
fi
else
echo ""
echo "No changes made. You can apply manually using the commands above."
fi
echo ""
print_success "Analysis complete!"
}
main