diff --git a/modules/security/live-attack-monitor.sh b/modules/security/live-attack-monitor.sh index d2fcbf9..260f9b0 100755 --- a/modules/security/live-attack-monitor.sh +++ b/modules/security/live-attack-monitor.sh @@ -435,8 +435,8 @@ draw_quick_actions() { if [ $has_ddos -eq 1 ] || [ $high_conn_count -gt 0 ]; then echo -e "${HIGH_COLOR} ⚠️ DDoS/SYN Flood Detected - Firewall Protection Recommended${NC}" echo -e "${MEDIUM_COLOR} → Enable SYNFLOOD protection: ${BOLD}csf -e SYNFLOOD${NC}" - echo -e "${MEDIUM_COLOR} → Set CT_LIMIT: ${BOLD}Edit /etc/csf/csf.conf → CT_LIMIT=\"100\"${NC}" - echo -e "${MEDIUM_COLOR} → Apply changes: ${BOLD}csf -r${NC}" + echo -e "${MEDIUM_COLOR} → Optimize CT_LIMIT: ${BOLD}Press 'c' to run CT_LIMIT optimizer${NC}" + echo -e "${MEDIUM_COLOR} → Or manual: ${BOLD}modules/security/optimize-ct-limit.sh${NC}" recommendations=1 fi @@ -454,7 +454,7 @@ draw_quick_actions() { echo "" fi - echo -e "${INFO_COLOR} Keys: 'b' Block IPs | 's' Stats | 'r' Refresh | 'h' Help | 'q' Quit${NC}" + echo -e "${INFO_COLOR} Keys: 'b' Block | 'c' CT_LIMIT | 's' Stats | 'r' Refresh | 'h' Help | 'q' Quit${NC}" echo -e "${MEDIUM_COLOR}└────────────────────────────────────────────────────────────────────────────┘${NC}" } @@ -1016,6 +1016,12 @@ while true; do b|B) show_blocking_menu ;; + c|C) + # Run CT_LIMIT optimizer + clear + "$SCRIPT_DIR/modules/security/optimize-ct-limit.sh" + read -p "Press Enter to return to monitor..." + ;; q|Q) cleanup ;; @@ -1036,6 +1042,7 @@ while true; do echo "" echo "Available Commands:" echo " ${BOLD}b${NC} - Open IP blocking menu (batch or individual)" + echo " ${BOLD}c${NC} - Run CT_LIMIT optimizer (analyze traffic & recommend limit)" echo " ${BOLD}s${NC} - Show IP reputation database statistics" echo " ${BOLD}r${NC} - Force refresh display" echo " ${BOLD}h${NC} - Show this help screen" diff --git a/modules/security/optimize-ct-limit.sh b/modules/security/optimize-ct-limit.sh new file mode 100755 index 0000000..faec87f --- /dev/null +++ b/modules/security/optimize-ct-limit.sh @@ -0,0 +1,455 @@ +#!/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 " + 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" </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