Initial commit: Server Management Toolkit v2.0
- Complete security menu restructure (3-mode: Analysis/Actions/Live) - Intelligent cPHulk enablement with CSF whitelist import - Live network security monitoring dashboard - Multi-source threat detection and classification - 50+ organized security tools across 4-level menu hierarchy - System health diagnostics with cPanel/WHM integration - Reference database for cross-module intelligence sharing
This commit is contained in:
Executable
+1790
File diff suppressed because it is too large
Load Diff
Executable
+566
@@ -0,0 +1,566 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Hardware Health Check
|
||||
# Comprehensive hardware diagnostics including SMART, memory, CPU, and sensors
|
||||
|
||||
# Get the script's directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
TOOLKIT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
# Source required libraries
|
||||
source "$TOOLKIT_ROOT/lib/common-functions.sh"
|
||||
source "$TOOLKIT_ROOT/lib/system-detect.sh"
|
||||
source "$TOOLKIT_ROOT/lib/reference-db.sh"
|
||||
|
||||
# Initialize system detection
|
||||
detect_system
|
||||
|
||||
# Load system info from reference database
|
||||
if [ -f "$TOOLKIT_ROOT/.sysref" ]; then
|
||||
SYS_HOSTNAME=$(grep "^SYS|HOSTNAME|" "$TOOLKIT_ROOT/.sysref" 2>/dev/null | cut -d'|' -f3)
|
||||
SYS_PANEL=$(grep "^SYS|CONTROL_PANEL|" "$TOOLKIT_ROOT/.sysref" 2>/dev/null | cut -d'|' -f3)
|
||||
SYS_PANEL_VER=$(grep "^SYS|CONTROL_PANEL|" "$TOOLKIT_ROOT/.sysref" 2>/dev/null | cut -d'|' -f4)
|
||||
SYS_OS=$(grep "^SYS|OS|" "$TOOLKIT_ROOT/.sysref" 2>/dev/null | cut -d'|' -f3)
|
||||
SYS_OS_VER=$(grep "^SYS|OS|" "$TOOLKIT_ROOT/.sysref" 2>/dev/null | cut -d'|' -f4)
|
||||
fi
|
||||
|
||||
# Color definitions
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
MAGENTA='\033[0;35m'
|
||||
CYAN='\033[0;36m'
|
||||
BOLD='\033[1m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Report file
|
||||
REPORT_FILE="/tmp/hardware_health_report_$(date +%Y%m%d_%H%M%S).txt"
|
||||
|
||||
# Analysis results storage
|
||||
declare -a FINDINGS=()
|
||||
|
||||
# Function to add finding
|
||||
add_finding() {
|
||||
local severity="$1"
|
||||
local title="$2"
|
||||
local details="$3"
|
||||
local recommendation="$4"
|
||||
|
||||
# Use @@@SEP@@@ as separator to avoid conflicts with content
|
||||
FINDINGS+=("[$severity] $title@@@SEP@@@$details@@@SEP@@@$recommendation")
|
||||
}
|
||||
|
||||
# Function to check if command exists
|
||||
command_exists() {
|
||||
command -v "$1" &>/dev/null
|
||||
}
|
||||
|
||||
# Function to check SMART status
|
||||
check_disk_smart() {
|
||||
echo -e "${CYAN}[INFO]${NC} Checking disk SMART status..."
|
||||
|
||||
if ! command_exists smartctl; then
|
||||
add_finding "INFO" "SMART Tools Not Installed" \
|
||||
"smartmontools is not installed - cannot check disk health" \
|
||||
"Install SMART tools: yum install smartmontools
|
||||
After installing, run: systemctl enable smartd && systemctl start smartd"
|
||||
return
|
||||
fi
|
||||
|
||||
# Find all disks
|
||||
local disks=$(lsblk -nd -o NAME,TYPE | awk '$2=="disk" {print "/dev/"$1}')
|
||||
|
||||
if [ -z "$disks" ]; then
|
||||
add_finding "WARNING" "No Disks Found" \
|
||||
"Could not detect any disk devices" \
|
||||
"Check system configuration: lsblk -a"
|
||||
return
|
||||
fi
|
||||
|
||||
local disk_count=0
|
||||
local healthy_count=0
|
||||
local warning_count=0
|
||||
local failed_count=0
|
||||
|
||||
for disk in $disks; do
|
||||
disk_count=$((disk_count + 1))
|
||||
|
||||
# Check if SMART is available
|
||||
if ! smartctl -i "$disk" &>/dev/null; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Get SMART health status
|
||||
local health=$(smartctl -H "$disk" 2>/dev/null | grep -i "SMART overall-health" | awk '{print $NF}')
|
||||
|
||||
# Get disk model and serial
|
||||
local model=$(smartctl -i "$disk" 2>/dev/null | grep "Device Model" | sed 's/Device Model:[ ]*//')
|
||||
[ -z "$model" ] && model=$(smartctl -i "$disk" 2>/dev/null | grep "Product:" | sed 's/Product:[ ]*//')
|
||||
local serial=$(smartctl -i "$disk" 2>/dev/null | grep "Serial Number" | sed 's/Serial Number:[ ]*//')
|
||||
|
||||
# Get key SMART attributes
|
||||
local reallocated=$(smartctl -A "$disk" 2>/dev/null | grep "Reallocated_Sector" | awk '{print $10}')
|
||||
local pending=$(smartctl -A "$disk" 2>/dev/null | grep "Current_Pending_Sector" | awk '{print $10}')
|
||||
local uncorrectable=$(smartctl -A "$disk" 2>/dev/null | grep "Offline_Uncorrectable" | awk '{print $10}')
|
||||
local temp=$(smartctl -A "$disk" 2>/dev/null | grep "Temperature_Celsius" | awk '{print $10}')
|
||||
local power_on=$(smartctl -A "$disk" 2>/dev/null | grep "Power_On_Hours" | awk '{print $10}')
|
||||
|
||||
# Determine severity
|
||||
if [[ "$health" =~ PASSED ]]; then
|
||||
# Check for warning signs even if passed
|
||||
if [ -n "$reallocated" ] && [ "$reallocated" -gt 0 ]; then
|
||||
warning_count=$((warning_count + 1))
|
||||
add_finding "WARNING" "Disk $disk: Reallocated Sectors Detected" \
|
||||
"Device: $disk
|
||||
Model: $model
|
||||
Serial: $serial
|
||||
Health: $health
|
||||
Reallocated Sectors: $reallocated
|
||||
Pending Sectors: ${pending:-0}
|
||||
Temperature: ${temp:-N/A}°C
|
||||
Power On Hours: ${power_on:-N/A}" \
|
||||
"Disk has reallocated sectors - sign of potential failure
|
||||
• Monitor closely: smartctl -A $disk
|
||||
• Plan for replacement
|
||||
• Ensure backups are current"
|
||||
elif [ -n "$pending" ] && [ "$pending" -gt 0 ]; then
|
||||
warning_count=$((warning_count + 1))
|
||||
add_finding "WARNING" "Disk $disk: Pending Sectors Detected" \
|
||||
"Device: $disk
|
||||
Model: $model
|
||||
Serial: $serial
|
||||
Health: $health
|
||||
Pending Sectors: $pending
|
||||
Temperature: ${temp:-N/A}°C
|
||||
Power On Hours: ${power_on:-N/A}" \
|
||||
"Disk has pending sectors - potential read/write issues
|
||||
• Monitor closely: smartctl -A $disk
|
||||
• Check system logs: grep -i '$disk' /var/log/messages
|
||||
• Consider replacement if increasing"
|
||||
else
|
||||
healthy_count=$((healthy_count + 1))
|
||||
add_finding "INFO" "Disk $disk: Healthy" \
|
||||
"Device: $disk
|
||||
Model: $model
|
||||
Serial: $serial
|
||||
Health: $health
|
||||
Reallocated Sectors: ${reallocated:-0}
|
||||
Pending Sectors: ${pending:-0}
|
||||
Temperature: ${temp:-N/A}°C
|
||||
Power On Hours: ${power_on:-N/A}" \
|
||||
"Disk is healthy - continue regular monitoring"
|
||||
fi
|
||||
else
|
||||
failed_count=$((failed_count + 1))
|
||||
add_finding "CRITICAL" "Disk $disk: SMART FAILURE" \
|
||||
"Device: $disk
|
||||
Model: $model
|
||||
Serial: $serial
|
||||
Health: ${health:-UNKNOWN}
|
||||
Reallocated Sectors: ${reallocated:-N/A}
|
||||
Pending Sectors: ${pending:-N/A}
|
||||
Uncorrectable Sectors: ${uncorrectable:-N/A}
|
||||
Temperature: ${temp:-N/A}°C" \
|
||||
"IMMEDIATE ACTION REQUIRED - Disk failing:
|
||||
• Backup all data immediately
|
||||
• Replace disk as soon as possible
|
||||
• Review SMART details: smartctl -a $disk
|
||||
• Check system logs: grep -i '$disk' /var/log/messages"
|
||||
fi
|
||||
done
|
||||
|
||||
# Summary finding
|
||||
add_finding "INFO" "Disk Health Summary" \
|
||||
"Total disks checked: $disk_count
|
||||
Healthy: $healthy_count
|
||||
Warning: $warning_count
|
||||
Failed: $failed_count" \
|
||||
"Regular SMART monitoring recommended: smartctl -a /dev/[disk]"
|
||||
}
|
||||
|
||||
# Function to check memory health
|
||||
check_memory_health() {
|
||||
echo -e "${CYAN}[INFO]${NC} Checking memory health..."
|
||||
|
||||
if ! command_exists dmidecode; then
|
||||
add_finding "INFO" "dmidecode Not Available" \
|
||||
"dmidecode is not installed - cannot check memory details" \
|
||||
"Install dmidecode: yum install dmidecode"
|
||||
return
|
||||
fi
|
||||
|
||||
# Get memory information
|
||||
local total_slots=$(dmidecode -t memory 2>/dev/null | grep -c "Memory Device$")
|
||||
local populated_slots=$(dmidecode -t memory 2>/dev/null | grep -A 20 "Memory Device" | grep "Size:" | grep -cv "No Module Installed")
|
||||
|
||||
# Get total memory
|
||||
local total_mem=$(free -h | grep "Mem:" | awk '{print $2}')
|
||||
|
||||
# Check for ECC
|
||||
local ecc_support=$(dmidecode -t memory 2>/dev/null | grep "Error Correction Type" | head -1 | grep -v "None" | wc -l)
|
||||
|
||||
# Check for memory errors in dmesg
|
||||
local mem_errors=$(dmesg | grep -i "memory error\|ecc error\|mcelog" | wc -l)
|
||||
|
||||
# Check hardware errors in system log
|
||||
local hw_mem_errors=$(grep -i "memory.*error\|ecc.*error" /var/log/messages 2>/dev/null | wc -l)
|
||||
|
||||
# Build memory details
|
||||
local mem_modules=$(dmidecode -t memory 2>/dev/null | grep -A 20 "Memory Device" | grep -E "Size:|Speed:|Type:|Manufacturer:|Part Number:" | sed 's/^[ \t]*/ /')
|
||||
|
||||
if [ "$mem_errors" -gt 0 ] || [ "$hw_mem_errors" -gt 0 ]; then
|
||||
# Get recent error samples
|
||||
local recent_errors=$(grep -i "memory.*error\|ecc.*error" /var/log/messages 2>/dev/null | tail -5 | sed 's/^/ /')
|
||||
|
||||
add_finding "CRITICAL" "Memory Errors Detected" \
|
||||
"Total Memory: $total_mem
|
||||
Slots: $populated_slots / $total_slots
|
||||
ECC Support: $([ $ecc_support -gt 0 ] && echo 'Yes' || echo 'No')
|
||||
Memory errors in dmesg: $mem_errors
|
||||
Hardware errors in logs: $hw_mem_errors
|
||||
|
||||
Recent errors:
|
||||
$recent_errors" \
|
||||
"Memory errors detected - investigate immediately:
|
||||
• Run memory test: Install and run memtest86+ (reboot required)
|
||||
• Check details: dmidecode -t memory
|
||||
• Review all errors: grep -i 'memory.*error' /var/log/messages
|
||||
• If ECC, check: dmidecode -t memory | grep -A 5 'Error Information'
|
||||
• Contact hosting provider if virtual machine
|
||||
• Replace faulty memory modules"
|
||||
else
|
||||
add_finding "INFO" "Memory Health Status" \
|
||||
"Total Memory: $total_mem
|
||||
Slots: $populated_slots / $total_slots
|
||||
ECC Support: $([ $ecc_support -gt 0 ] && echo 'Yes' || echo 'No')
|
||||
Memory errors: None detected
|
||||
|
||||
Installed Modules:
|
||||
$mem_modules" \
|
||||
"Memory appears healthy - no errors detected"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check CPU health
|
||||
check_cpu_health() {
|
||||
echo -e "${CYAN}[INFO]${NC} Checking CPU health..."
|
||||
|
||||
# Get CPU info
|
||||
local cpu_model=$(grep "model name" /proc/cpuinfo | head -1 | cut -d':' -f2 | sed 's/^[ \t]*//')
|
||||
local cpu_cores=$(grep -c "^processor" /proc/cpuinfo)
|
||||
local cpu_threads=$(nproc)
|
||||
|
||||
# Check for CPU errors in dmesg
|
||||
local cpu_errors=$(dmesg | grep -i "mce\|machine check\|cpu.*error" | wc -l)
|
||||
|
||||
# Check system log
|
||||
local hw_cpu_errors=$(grep -iE "mce|machine check exception|cpu.*error" /var/log/messages 2>/dev/null | wc -l)
|
||||
|
||||
# Get current CPU frequency
|
||||
local cpu_freq=""
|
||||
if [ -f "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" ]; then
|
||||
local freq_khz=$(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq)
|
||||
cpu_freq=$(echo "scale=2; $freq_khz / 1000000" | bc)" GHz"
|
||||
fi
|
||||
|
||||
# Check CPU temperature if sensors available
|
||||
local cpu_temp="N/A"
|
||||
if command_exists sensors; then
|
||||
cpu_temp=$(sensors 2>/dev/null | grep -E "Core 0|temp1" | head -1 | grep -oP '\+\K[0-9.]+' | head -1)
|
||||
[ -n "$cpu_temp" ] && cpu_temp="${cpu_temp}°C"
|
||||
fi
|
||||
|
||||
# Check load average
|
||||
local load_avg=$(uptime | awk -F'load average:' '{print $2}' | sed 's/^[ \t]*//')
|
||||
|
||||
if [ "$cpu_errors" -gt 0 ] || [ "$hw_cpu_errors" -gt 0 ]; then
|
||||
local recent_errors=$(grep -iE "mce|machine check|cpu.*error" /var/log/messages 2>/dev/null | tail -5 | sed 's/^/ /')
|
||||
|
||||
add_finding "CRITICAL" "CPU Errors Detected" \
|
||||
"CPU Model: $cpu_model
|
||||
Cores: $cpu_cores
|
||||
Threads: $cpu_threads
|
||||
Current Frequency: ${cpu_freq:-N/A}
|
||||
Temperature: $cpu_temp
|
||||
Load Average: $load_avg
|
||||
MCE/CPU errors in dmesg: $cpu_errors
|
||||
Hardware errors in logs: $hw_cpu_errors
|
||||
|
||||
Recent errors:
|
||||
$recent_errors" \
|
||||
"CPU errors detected - critical hardware issue:
|
||||
• Check full details: dmesg | grep -i mce
|
||||
• Review MCE logs: grep -i 'machine check' /var/log/messages
|
||||
• Check temperature: sensors (install: yum install lm_sensors)
|
||||
• Contact hosting provider/hardware vendor immediately
|
||||
• May indicate failing CPU or motherboard"
|
||||
else
|
||||
add_finding "INFO" "CPU Health Status" \
|
||||
"CPU Model: $cpu_model
|
||||
Cores: $cpu_cores
|
||||
Threads: $cpu_threads
|
||||
Current Frequency: ${cpu_freq:-N/A}
|
||||
Temperature: $cpu_temp
|
||||
Load Average: $load_avg
|
||||
Hardware errors: None detected" \
|
||||
"CPU appears healthy - no errors detected"
|
||||
fi
|
||||
|
||||
# Check if sensors are available for monitoring
|
||||
if ! command_exists sensors; then
|
||||
add_finding "INFO" "Temperature Monitoring Not Available" \
|
||||
"lm_sensors is not installed - cannot monitor CPU/hardware temperatures" \
|
||||
"Install sensors for temperature monitoring:
|
||||
• yum install lm_sensors
|
||||
• sensors-detect (answer YES to all)
|
||||
• sensors (view temperatures)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check system hardware errors
|
||||
check_hardware_errors() {
|
||||
echo -e "${CYAN}[INFO]${NC} Checking system hardware error logs..."
|
||||
|
||||
# Check for general hardware errors
|
||||
local hw_errors=$(grep -iE "hardware error|i/o error|ata.*error|scsi.*error" /var/log/messages 2>/dev/null | wc -l)
|
||||
|
||||
if [ "$hw_errors" -gt 0 ]; then
|
||||
local recent_errors=$(grep -iE "hardware error|i/o error|ata.*error|scsi.*error" /var/log/messages 2>/dev/null | tail -10 | sed 's/^/ /')
|
||||
|
||||
add_finding "WARNING" "Hardware Errors in System Log" \
|
||||
"Total hardware-related errors: $hw_errors
|
||||
|
||||
Recent errors (last 10):
|
||||
$recent_errors" \
|
||||
"Hardware errors detected in system logs:
|
||||
• Review full log: grep -iE 'hardware error|i/o error' /var/log/messages
|
||||
• Check dmesg: dmesg | grep -i error | tail -20
|
||||
• Identify failing component (disk, memory, CPU, etc.)
|
||||
• Run component-specific diagnostics
|
||||
• Contact hosting provider if persistent"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check RAID status
|
||||
check_raid_status() {
|
||||
echo -e "${CYAN}[INFO]${NC} Checking RAID status..."
|
||||
|
||||
local raid_found=false
|
||||
|
||||
# Check for software RAID (mdadm)
|
||||
if [ -f /proc/mdstat ] && grep -q "active" /proc/mdstat 2>/dev/null; then
|
||||
raid_found=true
|
||||
local raid_status=$(cat /proc/mdstat)
|
||||
local degraded=$(echo "$raid_status" | grep -c "\[.*_.*\]")
|
||||
|
||||
if [ "$degraded" -gt 0 ]; then
|
||||
add_finding "CRITICAL" "Software RAID Degraded" \
|
||||
"RAID array is degraded:
|
||||
|
||||
$raid_status" \
|
||||
"RAID array degraded - immediate action required:
|
||||
• Check details: cat /proc/mdstat
|
||||
• Identify failed drive: mdadm --detail /dev/md*
|
||||
• Replace failed drive and rebuild array
|
||||
• Ensure backups are current"
|
||||
else
|
||||
add_finding "INFO" "Software RAID Status" \
|
||||
"$raid_status" \
|
||||
"Software RAID is healthy"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check for hardware RAID (common controllers)
|
||||
if command_exists megacli; then
|
||||
raid_found=true
|
||||
local raid_info=$(megacli -LDInfo -Lall -aALL 2>/dev/null | grep -E "State|Virtual Drive")
|
||||
add_finding "INFO" "MegaRAID Status" \
|
||||
"$raid_info" \
|
||||
"Check details: megacli -LDInfo -Lall -aALL"
|
||||
fi
|
||||
|
||||
if ! $raid_found; then
|
||||
add_finding "INFO" "No RAID Detected" \
|
||||
"No software or hardware RAID arrays detected" \
|
||||
"System appears to use non-RAID storage"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check disk I/O errors
|
||||
check_disk_io_errors() {
|
||||
echo -e "${CYAN}[INFO]${NC} Checking disk I/O errors..."
|
||||
|
||||
# Check for I/O errors in dmesg
|
||||
local io_errors=$(dmesg | grep -iE "i/o error|blk_update_request|Buffer I/O error" | wc -l)
|
||||
|
||||
if [ "$io_errors" -gt 0 ]; then
|
||||
local recent_io_errors=$(dmesg | grep -iE "i/o error|blk_update_request|Buffer I/O error" | tail -10 | sed 's/^/ /')
|
||||
|
||||
add_finding "WARNING" "Disk I/O Errors Detected" \
|
||||
"Total I/O errors in dmesg: $io_errors
|
||||
|
||||
Recent I/O errors (last 10):
|
||||
$recent_io_errors" \
|
||||
"Disk I/O errors detected - indicates hardware or connection issues:
|
||||
• Check SMART status (see above)
|
||||
• Review dmesg: dmesg | grep -i 'i/o error'
|
||||
• Check cables and connections (if physical server)
|
||||
• Check for disk controller issues
|
||||
• May indicate failing disk or controller"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to generate report
|
||||
generate_report() {
|
||||
local report_content=""
|
||||
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="HARDWARE HEALTH CHECK - $(date '+%Y-%m-%d %H:%M:%S')"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="System: $SYS_HOSTNAME"$'\n'
|
||||
report_content+="Control Panel: $SYS_PANEL ${SYS_PANEL_VER:-unknown}"$'\n'
|
||||
report_content+="OS: $SYS_OS ${SYS_OS_VER:-unknown}"$'\n'
|
||||
report_content+=""$'\n'
|
||||
|
||||
# Group findings by category
|
||||
local -A categories
|
||||
categories["DISK"]=""
|
||||
categories["MEMORY"]=""
|
||||
categories["CPU"]=""
|
||||
categories["RAID"]=""
|
||||
categories["OTHER"]=""
|
||||
|
||||
for finding in "${FINDINGS[@]}"; do
|
||||
# Split by @@@SEP@@@ delimiter
|
||||
local severity_title="${finding%%@@@SEP@@@*}"
|
||||
local temp="${finding#*@@@SEP@@@}"
|
||||
local details="${temp%%@@@SEP@@@*}"
|
||||
local recommendation="${temp#*@@@SEP@@@}"
|
||||
|
||||
# Extract severity from [SEVERITY] Title format
|
||||
local severity=$(echo "$severity_title" | sed -n 's/^\[\([^]]*\)\].*/\1/p')
|
||||
local title=$(echo "$severity_title" | sed 's/^\[[^]]*\] //')
|
||||
|
||||
local category="OTHER"
|
||||
if [[ "$title" == *"Disk"* ]] || [[ "$title" == *"SMART"* ]] || [[ "$title" == *"I/O"* ]]; then
|
||||
category="DISK"
|
||||
elif [[ "$title" == *"Memory"* ]] || [[ "$title" == *"ECC"* ]]; then
|
||||
category="MEMORY"
|
||||
elif [[ "$title" == *"CPU"* ]] || [[ "$title" == *"MCE"* ]]; then
|
||||
category="CPU"
|
||||
elif [[ "$title" == *"RAID"* ]]; then
|
||||
category="RAID"
|
||||
fi
|
||||
|
||||
local entry=""
|
||||
entry+="[$severity] $title"$'\n'
|
||||
entry+="$details"$'\n'
|
||||
if [ -n "$recommendation" ]; then
|
||||
entry+="Recommendation:"$'\n'
|
||||
entry+="$recommendation"$'\n'
|
||||
fi
|
||||
entry+=""$'\n'
|
||||
entry+="------------------------------------------------------------------------------"$'\n'
|
||||
entry+=""$'\n'
|
||||
|
||||
categories[$category]+="$entry"
|
||||
done
|
||||
|
||||
# Output sections
|
||||
if [ -n "${categories[DISK]}" ]; then
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="DISK HEALTH & SMART STATUS"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="${categories[DISK]}"
|
||||
fi
|
||||
|
||||
if [ -n "${categories[MEMORY]}" ]; then
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="MEMORY HEALTH"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="${categories[MEMORY]}"
|
||||
fi
|
||||
|
||||
if [ -n "${categories[CPU]}" ]; then
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="CPU HEALTH"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="${categories[CPU]}"
|
||||
fi
|
||||
|
||||
if [ -n "${categories[RAID]}" ]; then
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="RAID STATUS"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="${categories[RAID]}"
|
||||
fi
|
||||
|
||||
if [ -n "${categories[OTHER]}" ]; then
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="OTHER HARDWARE FINDINGS"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="${categories[OTHER]}"
|
||||
fi
|
||||
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="NEXT STEPS"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="Priority Actions:"$'\n'
|
||||
report_content+=" 1. Address any CRITICAL issues immediately"$'\n'
|
||||
report_content+=" 2. Monitor WARNING issues closely"$'\n'
|
||||
report_content+=" 3. Schedule regular hardware health checks"$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="Additional Analysis Available:"$'\n'
|
||||
report_content+=" • System Health Check (Main Menu) for overall server health"$'\n'
|
||||
report_content+=" • Disk I/O Analyzer (Main Menu → Performance) for disk performance"$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="Report saved to: $REPORT_FILE"$'\n'
|
||||
report_content+=""$'\n'
|
||||
|
||||
echo "$report_content"
|
||||
echo "$report_content" > "$REPORT_FILE"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
show_banner
|
||||
echo -e "${MAGENTA}${BOLD}🔧 Hardware Health Check${NC}"
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
echo -e "${CYAN}[INFO]${NC} Starting comprehensive hardware diagnostics..."
|
||||
echo ""
|
||||
|
||||
# Run diagnostics
|
||||
check_disk_smart
|
||||
check_memory_health
|
||||
check_cpu_health
|
||||
check_hardware_errors
|
||||
check_raid_status
|
||||
check_disk_io_errors
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}[OK]${NC} Hardware diagnostics complete!"
|
||||
echo ""
|
||||
|
||||
# Generate and display report
|
||||
generate_report
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}[INFO]${NC} Full report saved to: ${CYAN}$REPORT_FILE${NC}"
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
press_enter
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main
|
||||
Executable
+422
@@ -0,0 +1,422 @@
|
||||
#!/bin/bash
|
||||
|
||||
#############################################################################
|
||||
# MySQL Query Analyzer
|
||||
# Deep forensics - identify problematic queries by domain and WordPress plugin
|
||||
#############################################################################
|
||||
|
||||
# Get script directory and load libraries
|
||||
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/user-manager.sh"
|
||||
source "$SCRIPT_DIR/lib/mysql-analyzer.sh"
|
||||
|
||||
# Require root
|
||||
require_root
|
||||
|
||||
# Create session temp directory
|
||||
create_temp_session
|
||||
|
||||
#############################################################################
|
||||
# MAIN ANALYSIS
|
||||
#############################################################################
|
||||
|
||||
main() {
|
||||
clear
|
||||
print_banner " MySQL Query Analyzer - Deep Forensics"
|
||||
|
||||
# Show system info
|
||||
echo -e "${BOLD}System Detected:${NC}"
|
||||
echo " Control Panel: $SYS_CONTROL_PANEL"
|
||||
echo " Database: $SYS_DB_TYPE $SYS_DB_VERSION"
|
||||
|
||||
# Count databases and WordPress sites
|
||||
local total_dbs=$(mysql -Ns -e "SHOW DATABASES" 2>/dev/null | grep -v "^information_schema$\|^mysql$\|^performance_schema$\|^sys$" | wc -l)
|
||||
local wp_sites=$(find $SYS_USER_HOME_BASE -name "wp-config.php" 2>/dev/null | wc -l)
|
||||
|
||||
echo " Databases: $total_dbs total"
|
||||
echo " WordPress Sites: $wp_sites detected"
|
||||
echo ""
|
||||
|
||||
# Analysis options menu
|
||||
echo -e "${BOLD}Analysis Options:${NC}"
|
||||
echo ""
|
||||
echo -e " ${GREEN}1)${NC} Full System Analysis (all databases)"
|
||||
echo -e " ${GREEN}2)${NC} Single User Analysis"
|
||||
echo -e " ${GREEN}3)${NC} Live Query Monitor (real-time)"
|
||||
echo -e " ${GREEN}4)${NC} Slow Query Log Analysis"
|
||||
echo -e " ${GREEN}5)${NC} Table Size Analysis"
|
||||
echo -e " ${GREEN}6)${NC} Quick Health Check"
|
||||
echo ""
|
||||
echo -e " ${RED}0)${NC} Back to menu"
|
||||
echo ""
|
||||
|
||||
read -p "Select option: " choice
|
||||
|
||||
case $choice in
|
||||
1) run_full_analysis ;;
|
||||
2) run_user_analysis ;;
|
||||
3) run_live_monitor ;;
|
||||
4) run_slow_query_analysis ;;
|
||||
5) run_table_size_analysis ;;
|
||||
6) run_quick_health_check ;;
|
||||
0) return 0 ;;
|
||||
*) print_error "Invalid option" ; sleep 2 ; main ;;
|
||||
esac
|
||||
}
|
||||
|
||||
#############################################################################
|
||||
# ANALYSIS MODES
|
||||
#############################################################################
|
||||
|
||||
run_full_analysis() {
|
||||
clear
|
||||
print_banner "Full System MySQL Analysis"
|
||||
|
||||
print_info "This will analyze all databases and queries system-wide..."
|
||||
echo ""
|
||||
|
||||
if ! confirm "Continue with full analysis?"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_section "Phase 1: Capturing Live Queries"
|
||||
local live_queries=$(capture_live_queries)
|
||||
|
||||
print_section "Phase 2: Parsing Slow Query Log"
|
||||
local slow_queries=$(parse_slow_query_log)
|
||||
|
||||
print_section "Phase 3: Analyzing Query Patterns"
|
||||
local problems=$(analyze_queries_for_problems "$live_queries")
|
||||
|
||||
print_section "Phase 4: Analyzing Slow Queries"
|
||||
analyze_queries_for_problems "$slow_queries" >> "${TEMP_SESSION_DIR}/query_problems.tmp"
|
||||
|
||||
print_section "Phase 5: Finding Largest Tables"
|
||||
local large_tables=$(find_largest_tables 20)
|
||||
|
||||
print_section "Phase 6: Generating Statistics"
|
||||
local stats=$(generate_plugin_statistics "${TEMP_SESSION_DIR}/query_problems.tmp")
|
||||
|
||||
echo ""
|
||||
print_section "Analysis Complete - Generating Report"
|
||||
echo ""
|
||||
|
||||
# Generate comprehensive report
|
||||
generate_full_report
|
||||
|
||||
echo ""
|
||||
read -p "Press Enter to continue..."
|
||||
}
|
||||
|
||||
run_user_analysis() {
|
||||
clear
|
||||
print_banner "Per-User MySQL Analysis"
|
||||
|
||||
# Select user
|
||||
local selected_user=$(select_user_interactive "Select user to analyze")
|
||||
|
||||
if [ $? -ne 0 ] || [ -z "$selected_user" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ "$selected_user" = "ALL" ]; then
|
||||
run_full_analysis
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_section "Analyzing user: $selected_user"
|
||||
|
||||
# Get user databases
|
||||
local user_dbs=$(get_user_databases "$selected_user")
|
||||
local db_count=$(echo "$user_dbs" | wc -l)
|
||||
|
||||
echo " Databases found: $db_count"
|
||||
echo "$user_dbs" | sed 's/^/ - /'
|
||||
echo ""
|
||||
|
||||
# Analyze each database
|
||||
for db in $user_dbs; do
|
||||
analyze_database "$db" "$selected_user"
|
||||
done
|
||||
|
||||
echo ""
|
||||
read -p "Press Enter to continue..."
|
||||
}
|
||||
|
||||
run_live_monitor() {
|
||||
clear
|
||||
print_banner "Live Query Monitor"
|
||||
|
||||
print_info "Monitoring active MySQL queries (press Ctrl+C to stop)"
|
||||
echo ""
|
||||
|
||||
while true; do
|
||||
clear
|
||||
print_section "Active Queries - $(date '+%H:%M:%S')"
|
||||
|
||||
mysql -e "SHOW FULL PROCESSLIST" 2>/dev/null | while read id user host db command time state info; do
|
||||
if [ "$command" != "Sleep" ] && [ -n "$info" ] && [ "$info" != "SHOW FULL PROCESSLIST" ]; then
|
||||
local domain=$(get_database_domain "$db")
|
||||
local plugin=$(identify_plugin_from_table "$(extract_tables_from_query "$info" | head -1)")
|
||||
|
||||
echo -e "${YELLOW}DB: $db${NC} (${CYAN}$domain${NC}) - ${GREEN}$plugin${NC}"
|
||||
echo " Time: ${time}s"
|
||||
echo " Query: $(echo "$info" | cut -c1-100)..."
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
|
||||
sleep 2
|
||||
done
|
||||
}
|
||||
|
||||
run_slow_query_analysis() {
|
||||
clear
|
||||
print_banner "Slow Query Log Analysis"
|
||||
|
||||
print_info "Analyzing slow query log..."
|
||||
echo ""
|
||||
|
||||
local slow_log=$(parse_slow_query_log)
|
||||
|
||||
if [ ! -s "$slow_log" ]; then
|
||||
print_warning "No slow queries found or slow query log is not enabled"
|
||||
echo ""
|
||||
echo "To enable slow query log:"
|
||||
echo " 1. Edit /etc/my.cnf or /etc/mysql/my.cnf"
|
||||
echo " 2. Add under [mysqld]:"
|
||||
echo " slow_query_log = 1"
|
||||
echo " slow_query_log_file = /var/log/mysql/slow.log"
|
||||
echo " long_query_time = 2"
|
||||
echo " 3. Restart MySQL: systemctl restart mysql"
|
||||
echo ""
|
||||
read -p "Press Enter to continue..."
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Analyze slow queries
|
||||
local problems=$(analyze_queries_for_problems "$slow_log")
|
||||
|
||||
# Show top 10 slowest
|
||||
print_section "Top 10 Problematic Slow Queries"
|
||||
echo ""
|
||||
|
||||
grep "^PROBLEM" "$problems" 2>/dev/null | head -10 | while IFS='|' read -r type domain owner db plugin table issue query_time query; do
|
||||
echo -e "${RED}[$query_time s] $plugin on $domain${NC}"
|
||||
echo " Database: $db | Table: $table"
|
||||
echo " Issue: $issue"
|
||||
echo " Recommended Fix:"
|
||||
recommend_fix "$issue" "$db" "$table" "$plugin" | sed 's/^/ /'
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo ""
|
||||
read -p "Press Enter to continue..."
|
||||
}
|
||||
|
||||
run_table_size_analysis() {
|
||||
clear
|
||||
print_banner "Table Size Analysis"
|
||||
|
||||
print_info "Finding largest tables and checking for bloat..."
|
||||
echo ""
|
||||
|
||||
local large_tables=$(find_largest_tables 30)
|
||||
|
||||
print_section "Top 30 Largest Tables"
|
||||
echo ""
|
||||
|
||||
printf "${BOLD}%-40s %-30s %15s %10s %20s${NC}\n" "Database" "Table" "Size (MB)" "Bloat" "Plugin"
|
||||
echo "──────────────────────────────────────────────────────────────────────────────────────────────────────────────────"
|
||||
|
||||
while read -r db_name table_name size_mb; do
|
||||
local plugin=$(identify_plugin_from_table "$table_name")
|
||||
local domain=$(get_database_domain "$db_name")
|
||||
local bloat=$(check_table_bloat "$db_name" "$table_name")
|
||||
|
||||
local bloat_color="${GREEN}"
|
||||
[ "$bloat" != "OK" ] && bloat_color="${RED}"
|
||||
|
||||
printf "%-40s %-30s %15s ${bloat_color}%10s${NC} %20s\n" \
|
||||
"$db_name" "$table_name" "${size_mb} MB" "$bloat" "$plugin"
|
||||
|
||||
# Recommend optimization if bloated
|
||||
if [ "$bloat" != "OK" ]; then
|
||||
echo " → Recommended: OPTIMIZE TABLE \`$db_name\`.\`$table_name\`;"
|
||||
fi
|
||||
done < "$large_tables"
|
||||
|
||||
echo ""
|
||||
|
||||
# Offer to optimize bloated tables
|
||||
echo ""
|
||||
if confirm "Optimize bloated tables now? (This may take time)"; then
|
||||
echo ""
|
||||
while read -r db_name table_name size_mb; do
|
||||
local bloat=$(check_table_bloat "$db_name" "$table_name")
|
||||
if [ "$bloat" != "OK" ]; then
|
||||
print_info "Optimizing $db_name.$table_name..."
|
||||
mysql -e "OPTIMIZE TABLE \`$db_name\`.\`$table_name\`" 2>/dev/null
|
||||
print_success "Optimized $db_name.$table_name"
|
||||
fi
|
||||
done < "$large_tables"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
read -p "Press Enter to continue..."
|
||||
}
|
||||
|
||||
run_quick_health_check() {
|
||||
clear
|
||||
print_banner "Quick MySQL Health Check"
|
||||
|
||||
echo ""
|
||||
print_section "Database Server Status"
|
||||
echo ""
|
||||
|
||||
# Check if MySQL is running
|
||||
if systemctl is-active --quiet mysql 2>/dev/null || systemctl is-active --quiet mariadb 2>/dev/null; then
|
||||
print_success "MySQL/MariaDB service is running"
|
||||
else
|
||||
print_error "MySQL/MariaDB service is NOT running"
|
||||
fi
|
||||
|
||||
# Get current connections
|
||||
local connections=$(mysql -Ns -e "SHOW STATUS LIKE 'Threads_connected'" | awk '{print $2}')
|
||||
local max_connections=$(mysql -Ns -e "SHOW VARIABLES LIKE 'max_connections'" | awk '{print $2}')
|
||||
local conn_percent=$((connections * 100 / max_connections))
|
||||
|
||||
echo " Active Connections: $connections / $max_connections (${conn_percent}%)"
|
||||
|
||||
if [ $conn_percent -gt 80 ]; then
|
||||
print_warning "Connection usage is high (${conn_percent}%)"
|
||||
fi
|
||||
|
||||
# Check slow queries
|
||||
local slow_queries_count=$(mysql -Ns -e "SHOW STATUS LIKE 'Slow_queries'" | awk '{print $2}')
|
||||
echo " Slow Queries (total): $slow_queries_count"
|
||||
|
||||
# Check aborted connections
|
||||
local aborted=$(mysql -Ns -e "SHOW STATUS LIKE 'Aborted_connects'" | awk '{print $2}')
|
||||
echo " Aborted Connections: $aborted"
|
||||
|
||||
if [ "$aborted" -gt 100 ]; then
|
||||
print_warning "High number of aborted connections - check for connection issues"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_section "Top 5 Largest Databases"
|
||||
echo ""
|
||||
|
||||
mysql -Ns -e "SELECT table_schema,
|
||||
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS size_mb
|
||||
FROM information_schema.TABLES
|
||||
WHERE table_schema NOT IN ('information_schema', 'mysql', 'performance_schema', 'sys')
|
||||
GROUP BY table_schema
|
||||
ORDER BY size_mb DESC
|
||||
LIMIT 5" 2>/dev/null | while read db size; do
|
||||
local owner=$(get_database_owner "$db")
|
||||
local domain=$(get_database_domain "$db")
|
||||
printf " %-30s %10s MB (%s - %s)\n" "$db" "$size" "$owner" "$domain"
|
||||
done
|
||||
|
||||
echo ""
|
||||
print_section "Current Resource Usage"
|
||||
echo ""
|
||||
|
||||
echo " CPU Usage: ${CPU_USED}%"
|
||||
echo " Memory Usage: ${MEM_PERCENT}%"
|
||||
echo " Load Average: $LOAD_AVERAGE (${LOAD_PERCENT}% of capacity)"
|
||||
|
||||
echo ""
|
||||
read -p "Press Enter to continue..."
|
||||
}
|
||||
|
||||
#############################################################################
|
||||
# HELPER FUNCTIONS
|
||||
#############################################################################
|
||||
|
||||
analyze_database() {
|
||||
local db_name="$1"
|
||||
local username="$2"
|
||||
|
||||
print_section "Database: $db_name"
|
||||
|
||||
# Get tables
|
||||
local tables=$(get_database_tables "$db_name")
|
||||
local table_count=$(echo "$tables" | wc -l)
|
||||
|
||||
echo " Tables: $table_count"
|
||||
|
||||
# Identify plugins
|
||||
local plugins=""
|
||||
for table in $tables; do
|
||||
local plugin=$(identify_plugin_from_table "$table")
|
||||
if [ "$plugin" != "WordPress Core" ] && [ "$plugin" != "Unknown Plugin" ]; then
|
||||
plugins="$plugins\n - $plugin"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$plugins" ]; then
|
||||
echo -e " Plugins detected:$plugins" | sort -u
|
||||
fi
|
||||
|
||||
# Get database size
|
||||
local db_size=$(mysql -Ns -e "SELECT ROUND(SUM(data_length + index_length) / 1024 / 1024, 2)
|
||||
FROM information_schema.TABLES
|
||||
WHERE table_schema='$db_name'" 2>/dev/null)
|
||||
|
||||
echo " Size: ${db_size} MB"
|
||||
echo ""
|
||||
}
|
||||
|
||||
generate_full_report() {
|
||||
local report_file="/tmp/mysql_analysis_$(date +%Y%m%d_%H%M%S).txt"
|
||||
local problems_file="${TEMP_SESSION_DIR}/query_problems.tmp"
|
||||
|
||||
exec > >(tee "$report_file")
|
||||
|
||||
print_banner "MySQL Deep Analysis Report"
|
||||
|
||||
echo "Generated: $(date)"
|
||||
echo "Server: $(hostname)"
|
||||
echo "Control Panel: $SYS_CONTROL_PANEL"
|
||||
echo "Database: $SYS_DB_TYPE $SYS_DB_VERSION"
|
||||
echo ""
|
||||
|
||||
# Critical issues
|
||||
local critical_count=$(grep -c "^PROBLEM" "$problems_file" 2>/dev/null || echo 0)
|
||||
|
||||
print_section "CRITICAL ISSUES: $critical_count found"
|
||||
echo ""
|
||||
|
||||
if [ "$critical_count" -gt 0 ]; then
|
||||
grep "^PROBLEM" "$problems_file" | nl | while read num type domain owner db plugin table issue query_time query; do
|
||||
echo -e "${RED}[$num] $plugin on $domain${NC}"
|
||||
echo " Database: $db"
|
||||
echo " Table: $table"
|
||||
echo " Issue: $issue"
|
||||
[ -n "$query_time" ] && [ "$query_time" != "PROBLEM" ] && echo " Query Time: ${query_time}s"
|
||||
echo " Recommended Fix:"
|
||||
recommend_fix "$issue" "$db" "$table" "$plugin" | sed 's/^/ /'
|
||||
echo ""
|
||||
done
|
||||
else
|
||||
print_success "No critical issues detected"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_info "Full report saved to: $report_file"
|
||||
|
||||
exec > /dev/tty
|
||||
}
|
||||
|
||||
#############################################################################
|
||||
# RUN
|
||||
#############################################################################
|
||||
|
||||
main
|
||||
+643
@@ -0,0 +1,643 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Network & Bandwidth Analyzer
|
||||
# Analyzes bandwidth usage, network performance, and traffic patterns
|
||||
|
||||
# Get the script's directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
TOOLKIT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
# Source required libraries
|
||||
source "$TOOLKIT_ROOT/lib/common-functions.sh"
|
||||
source "$TOOLKIT_ROOT/lib/system-detect.sh"
|
||||
source "$TOOLKIT_ROOT/lib/reference-db.sh"
|
||||
|
||||
# Initialize system detection
|
||||
detect_system
|
||||
|
||||
# Load system info from reference database
|
||||
if [ -f "$TOOLKIT_ROOT/.sysref" ]; then
|
||||
SYS_HOSTNAME=$(grep "^SYS|HOSTNAME|" "$TOOLKIT_ROOT/.sysref" 2>/dev/null | cut -d'|' -f3)
|
||||
SYS_PANEL=$(grep "^SYS|CONTROL_PANEL|" "$TOOLKIT_ROOT/.sysref" 2>/dev/null | cut -d'|' -f3)
|
||||
SYS_PANEL_VER=$(grep "^SYS|CONTROL_PANEL|" "$TOOLKIT_ROOT/.sysref" 2>/dev/null | cut -d'|' -f4)
|
||||
SYS_OS=$(grep "^SYS|OS|" "$TOOLKIT_ROOT/.sysref" 2>/dev/null | cut -d'|' -f3)
|
||||
SYS_OS_VER=$(grep "^SYS|OS|" "$TOOLKIT_ROOT/.sysref" 2>/dev/null | cut -d'|' -f4)
|
||||
fi
|
||||
|
||||
# Color definitions
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
MAGENTA='\033[0;35m'
|
||||
CYAN='\033[0;36m'
|
||||
BOLD='\033[1m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Report file
|
||||
REPORT_FILE="/tmp/network_bandwidth_report_$(date +%Y%m%d_%H%M%S).txt"
|
||||
|
||||
# Analysis results storage
|
||||
declare -a FINDINGS=()
|
||||
declare -a RECOMMENDATIONS=()
|
||||
|
||||
# Function to add finding
|
||||
add_finding() {
|
||||
local severity="$1"
|
||||
local title="$2"
|
||||
local details="$3"
|
||||
local recommendation="$4"
|
||||
|
||||
# Use @@@SEP@@@ as separator to avoid conflicts with content
|
||||
FINDINGS+=("[$severity] $title@@@SEP@@@$details@@@SEP@@@$recommendation")
|
||||
}
|
||||
|
||||
# Function to check if command exists
|
||||
command_exists() {
|
||||
command -v "$1" &>/dev/null
|
||||
}
|
||||
|
||||
# Function to install vnstat if needed
|
||||
check_and_offer_vnstat() {
|
||||
if ! command_exists vnstat; then
|
||||
echo -e "${YELLOW}[INFO]${NC} vnstat is not installed. vnstat provides historical bandwidth tracking."
|
||||
echo ""
|
||||
read -p "Would you like to install vnstat now? (y/n): " install_vnstat
|
||||
if [[ "$install_vnstat" =~ ^[Yy]$ ]]; then
|
||||
echo -e "${CYAN}[INFO]${NC} Installing vnstat..."
|
||||
if command_exists yum; then
|
||||
yum install -y vnstat
|
||||
elif command_exists apt-get; then
|
||||
apt-get update && apt-get install -y vnstat
|
||||
else
|
||||
echo -e "${RED}[ERROR]${NC} Could not determine package manager"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Initialize vnstat database
|
||||
echo -e "${CYAN}[INFO]${NC} Initializing vnstat database..."
|
||||
systemctl enable vnstat --now 2>/dev/null || service vnstat start 2>/dev/null
|
||||
sleep 2
|
||||
echo -e "${GREEN}[OK]${NC} vnstat installed and started!"
|
||||
echo -e "${YELLOW}[NOTE]${NC} vnstat needs time to collect data. Initial stats will be limited."
|
||||
echo ""
|
||||
else
|
||||
echo -e "${YELLOW}[INFO]${NC} Skipping vnstat installation. Historical bandwidth data will not be available."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to analyze bandwidth with vnstat
|
||||
analyze_bandwidth_vnstat() {
|
||||
echo -e "${CYAN}[INFO]${NC} Analyzing historical bandwidth usage..."
|
||||
|
||||
if ! check_and_offer_vnstat; then
|
||||
add_finding "INFO" "Historical Bandwidth Tracking Not Available" \
|
||||
"vnstat is not installed - cannot show historical bandwidth data" \
|
||||
"Install vnstat for bandwidth tracking: yum install vnstat"
|
||||
return
|
||||
fi
|
||||
|
||||
# Get primary interface
|
||||
local interface=$(ip route | grep default | awk '{print $5}' | head -1)
|
||||
|
||||
if [ -z "$interface" ]; then
|
||||
add_finding "WARNING" "Cannot Determine Network Interface" \
|
||||
"Unable to detect primary network interface" \
|
||||
"Check network configuration: ip route show"
|
||||
return
|
||||
fi
|
||||
|
||||
# Check if vnstat has data for this interface
|
||||
if ! vnstat -i "$interface" &>/dev/null; then
|
||||
echo -e "${YELLOW}[INFO]${NC} Initializing vnstat for interface $interface..."
|
||||
vnstat --create -i "$interface" 2>/dev/null
|
||||
echo -e "${YELLOW}[NOTE]${NC} vnstat database created. Data collection will begin now."
|
||||
echo " Run this tool again after some time to see bandwidth statistics."
|
||||
echo ""
|
||||
add_finding "INFO" "Bandwidth Monitoring Initialized" \
|
||||
"vnstat database created for interface $interface
|
||||
Data collection started - statistics will be available after some usage" \
|
||||
"Run this analyzer again in 1+ hours to see bandwidth trends"
|
||||
return
|
||||
fi
|
||||
|
||||
# Get monthly bandwidth
|
||||
local monthly_data=$(vnstat -i "$interface" -m --json 2>/dev/null)
|
||||
|
||||
if [ -n "$monthly_data" ]; then
|
||||
# Extract current month data using basic parsing (fallback if jq not available)
|
||||
local current_month_rx=$(vnstat -i "$interface" -m | grep "$(date +%Y-%m)" | awk '{print $3, $4}' | head -1)
|
||||
local current_month_tx=$(vnstat -i "$interface" -m | grep "$(date +%Y-%m)" | awk '{print $6, $7}' | head -1)
|
||||
local current_month_total=$(vnstat -i "$interface" -m | grep "$(date +%Y-%m)" | awk '{print $9, $10}' | head -1)
|
||||
|
||||
if [ -n "$current_month_total" ]; then
|
||||
add_finding "INFO" "Monthly Bandwidth Usage ($(date +%B))" \
|
||||
"Interface: $interface
|
||||
Download: $current_month_rx
|
||||
Upload: $current_month_tx
|
||||
Total: $current_month_total" \
|
||||
"Monitor bandwidth trends daily to prevent overage"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Get daily bandwidth
|
||||
local daily_summary=$(vnstat -i "$interface" -d | tail -n 15 | head -n 10)
|
||||
if [ -n "$daily_summary" ]; then
|
||||
add_finding "INFO" "Daily Bandwidth Summary (Last 7 Days)" \
|
||||
"$daily_summary" \
|
||||
"Review daily patterns to identify unusual spikes"
|
||||
fi
|
||||
|
||||
# Get hourly bandwidth for today
|
||||
local hourly_summary=$(vnstat -i "$interface" -h | tail -n 8)
|
||||
if [ -n "$hourly_summary" ]; then
|
||||
add_finding "INFO" "Hourly Bandwidth (Last 24 Hours)" \
|
||||
"$hourly_summary" \
|
||||
"Hourly view helps identify peak usage times"
|
||||
fi
|
||||
|
||||
# Check for high bandwidth usage patterns
|
||||
local today_total=$(vnstat -i "$interface" -d | grep "$(date +%Y-%m-%d)" | awk '{print $9}')
|
||||
local today_value=$(echo "$today_total" | awk '{print $1}')
|
||||
local today_unit=$(echo "$today_total" | awk '{print $2}')
|
||||
|
||||
if [ "$today_unit" = "GiB" ] && [ -n "$today_value" ]; then
|
||||
if (( $(echo "$today_value > 50" | bc -l 2>/dev/null || echo 0) )); then
|
||||
add_finding "WARNING" "High Daily Bandwidth Usage" \
|
||||
"Today's usage: $today_total
|
||||
This is significantly higher than typical usage" \
|
||||
"Investigate traffic sources:
|
||||
• Check top bandwidth consumers (see analysis below)
|
||||
• Review Apache logs for unusual traffic
|
||||
• Check for backups or updates running
|
||||
• Look for bot/crawler traffic"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to analyze Apache/web server traffic
|
||||
analyze_web_traffic() {
|
||||
echo -e "${CYAN}[INFO]${NC} Analyzing web server traffic patterns..."
|
||||
|
||||
# Find Apache log directory
|
||||
local log_dir=""
|
||||
if [ -d "/var/log/apache2/domlogs" ]; then
|
||||
log_dir="/var/log/apache2/domlogs"
|
||||
elif [ -d "/etc/apache2/logs/domlogs" ]; then
|
||||
log_dir="/etc/apache2/logs/domlogs"
|
||||
elif [ -d "/var/log/httpd" ]; then
|
||||
log_dir="/var/log/httpd"
|
||||
fi
|
||||
|
||||
if [ -z "$log_dir" ] || [ ! -d "$log_dir" ]; then
|
||||
add_finding "INFO" "Web Server Logs Not Found" \
|
||||
"Could not locate Apache/web server logs" \
|
||||
"Web traffic analysis requires Apache logs"
|
||||
return
|
||||
fi
|
||||
|
||||
# Analyze top requesting IPs
|
||||
echo -e "${CYAN}[INFO]${NC} Finding top requesting IP addresses..."
|
||||
local top_ips=$(find "$log_dir" -name "*.log" -type f -mtime -1 -exec cat {} \; 2>/dev/null | \
|
||||
awk '{print $1}' | sort | uniq -c | sort -rn | head -10 | \
|
||||
awk '{printf " • %8s requests - %s\n", $1, $2}')
|
||||
|
||||
if [ -n "$top_ips" ]; then
|
||||
add_finding "INFO" "Top Requesting IPs (Last 24 Hours)" \
|
||||
"$top_ips" \
|
||||
"Investigate high-volume IPs:
|
||||
• Check if legitimate (search engines, monitoring)
|
||||
• Look for bot patterns in User-Agent
|
||||
• Consider rate limiting if abusive
|
||||
• Use Bot Analyzer for detailed analysis"
|
||||
fi
|
||||
|
||||
# Analyze bandwidth by domain (if cPanel)
|
||||
if [ "$SYS_PANEL" = "cpanel" ]; then
|
||||
echo -e "${CYAN}[INFO]${NC} Analyzing per-domain bandwidth..."
|
||||
local domain_bandwidth=""
|
||||
|
||||
for logfile in "$log_dir"/*.log; do
|
||||
[ -f "$logfile" ] || continue
|
||||
local domain=$(basename "$logfile" .log)
|
||||
local bytes=$(awk '{sum+=$10} END {print sum}' "$logfile" 2>/dev/null || echo "0")
|
||||
|
||||
if [ "$bytes" -gt 0 ]; then
|
||||
local mb=$(echo "scale=2; $bytes / 1048576" | bc 2>/dev/null || echo "0")
|
||||
domain_bandwidth+=" • $(printf '%-40s %10.2f MB' "$domain" "$mb")"$'\n'
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$domain_bandwidth" ]; then
|
||||
domain_bandwidth=$(echo "$domain_bandwidth" | sort -k2 -rn | head -10)
|
||||
add_finding "INFO" "Top Bandwidth-Consuming Domains (Last 24 Hours)" \
|
||||
"$domain_bandwidth" \
|
||||
"Review high-bandwidth domains for:
|
||||
• Large file downloads
|
||||
• Media streaming
|
||||
• Bot/crawler traffic
|
||||
• Possible attacks or abuse"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Analyze top requested URLs/files
|
||||
echo -e "${CYAN}[INFO]${NC} Finding most requested URLs..."
|
||||
local top_urls=$(find "$log_dir" -name "*.log" -type f -mtime -1 -exec cat {} \; 2>/dev/null | \
|
||||
awk '{print $7}' | sort | uniq -c | sort -rn | head -10 | \
|
||||
awk '{printf " • %8s requests - %s\n", $1, $2}')
|
||||
|
||||
if [ -n "$top_urls" ]; then
|
||||
add_finding "INFO" "Most Requested URLs (Last 24 Hours)" \
|
||||
"$top_urls" \
|
||||
"Check for:
|
||||
• Broken links (404s)
|
||||
• Bot crawling patterns
|
||||
• Resource-intensive endpoints
|
||||
• Potential attack vectors"
|
||||
fi
|
||||
|
||||
# Check for high bandwidth files
|
||||
echo -e "${CYAN}[INFO]${NC} Finding large bandwidth-consuming requests..."
|
||||
local large_transfers=$(find "$log_dir" -name "*.log" -type f -mtime -1 -exec cat {} \; 2>/dev/null | \
|
||||
awk '$10 > 10485760 {sum+=$10; count++} END {if (count > 0) printf " • Total large files: %d\n • Combined size: %.2f GB\n", count, sum/1073741824}')
|
||||
|
||||
if [ -n "$large_transfers" ]; then
|
||||
add_finding "INFO" "Large File Transfers (>10MB each)" \
|
||||
"$large_transfers" \
|
||||
"Large file downloads can consume significant bandwidth
|
||||
• Consider CDN for large static files
|
||||
• Implement download throttling
|
||||
• Check for legitimate vs bot downloads"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to analyze network connections
|
||||
analyze_network_connections() {
|
||||
echo -e "${CYAN}[INFO]${NC} Analyzing network connections..."
|
||||
|
||||
# Count connections by state
|
||||
local conn_states=$(netstat -an 2>/dev/null | awk '/^tcp/ {print $6}' | sort | uniq -c | sort -rn | \
|
||||
awk '{printf " • %-20s %s\n", $2, $1}')
|
||||
|
||||
if [ -n "$conn_states" ]; then
|
||||
add_finding "INFO" "TCP Connection States" \
|
||||
"$conn_states" \
|
||||
"Monitor connection states:
|
||||
• High TIME_WAIT: Normal after busy traffic
|
||||
• High CLOSE_WAIT: Possible application issues
|
||||
• High SYN_RECV: Possible SYN flood attack"
|
||||
fi
|
||||
|
||||
# Count total connections
|
||||
local total_conn=$(netstat -an 2>/dev/null | grep -c "^tcp")
|
||||
if [ "$total_conn" -gt 1000 ]; then
|
||||
add_finding "WARNING" "High Number of TCP Connections" \
|
||||
"Current TCP connections: $total_conn
|
||||
This may indicate high traffic or connection leak" \
|
||||
"Investigate connection sources:
|
||||
• netstat -an | grep ESTABLISHED | awk '{print \$5}' | cut -d: -f1 | sort | uniq -c | sort -rn
|
||||
• Check for connection pooling issues
|
||||
• Review application connection handling"
|
||||
fi
|
||||
|
||||
# Top connecting IPs
|
||||
local top_conn_ips=$(netstat -an 2>/dev/null | grep ESTABLISHED | awk '{print $5}' | cut -d: -f1 | \
|
||||
sort | uniq -c | sort -rn | head -10 | awk '{printf " • %8s connections - %s\n", $1, $2}')
|
||||
|
||||
if [ -n "$top_conn_ips" ]; then
|
||||
add_finding "INFO" "Top Connected IP Addresses" \
|
||||
"$top_conn_ips" \
|
||||
"Review connection patterns from these IPs"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check network performance
|
||||
analyze_network_performance() {
|
||||
echo -e "${CYAN}[INFO]${NC} Analyzing network performance..."
|
||||
|
||||
# Get primary interface
|
||||
local interface=$(ip route | grep default | awk '{print $5}' | head -1)
|
||||
|
||||
if [ -z "$interface" ]; then
|
||||
add_finding "WARNING" "Cannot Determine Network Interface" \
|
||||
"Unable to detect primary network interface" \
|
||||
"Check network configuration: ip route show"
|
||||
return
|
||||
fi
|
||||
|
||||
# Get interface statistics
|
||||
local rx_errors=$(cat "/sys/class/net/$interface/statistics/rx_errors" 2>/dev/null || echo "0")
|
||||
local tx_errors=$(cat "/sys/class/net/$interface/statistics/tx_errors" 2>/dev/null || echo "0")
|
||||
local rx_dropped=$(cat "/sys/class/net/$interface/statistics/rx_dropped" 2>/dev/null || echo "0")
|
||||
local tx_dropped=$(cat "/sys/class/net/$interface/statistics/tx_dropped" 2>/dev/null || echo "0")
|
||||
|
||||
if [ "$rx_errors" -gt 100 ] || [ "$tx_errors" -gt 100 ]; then
|
||||
add_finding "WARNING" "Network Interface Errors Detected" \
|
||||
"Interface: $interface
|
||||
RX Errors: $rx_errors
|
||||
TX Errors: $tx_errors
|
||||
RX Dropped: $rx_dropped
|
||||
TX Dropped: $tx_dropped" \
|
||||
"Network errors may indicate:
|
||||
• Hardware issues (cable, NIC)
|
||||
• Driver problems
|
||||
• Network congestion
|
||||
Check: dmesg | grep -i $interface | tail -20"
|
||||
fi
|
||||
|
||||
# Get MTU
|
||||
local mtu=$(ip link show "$interface" 2>/dev/null | grep mtu | awk '{print $5}')
|
||||
if [ -n "$mtu" ]; then
|
||||
if [ "$mtu" -ne 1500 ] && [ "$mtu" -ne 9000 ]; then
|
||||
add_finding "INFO" "Non-Standard MTU Detected" \
|
||||
"Interface: $interface
|
||||
Current MTU: $mtu
|
||||
Standard MTU is typically 1500 (or 9000 for jumbo frames)" \
|
||||
"Ensure MTU matches your network infrastructure
|
||||
• Test MTU: ping -M do -s 1472 8.8.8.8
|
||||
• Set MTU: ip link set $interface mtu 1500"
|
||||
else
|
||||
add_finding "INFO" "Network Interface Configuration" \
|
||||
"Interface: $interface
|
||||
MTU: $mtu
|
||||
RX Errors: $rx_errors
|
||||
TX Errors: $tx_errors
|
||||
RX Dropped: $rx_dropped
|
||||
TX Dropped: $tx_dropped" \
|
||||
"Network interface appears healthy"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check TCP statistics
|
||||
local tcp_retrans=$(netstat -s 2>/dev/null | grep "segments retransmitted" | awk '{print $1}' || echo "0")
|
||||
local tcp_out=$(netstat -s 2>/dev/null | grep "segments sent out" | awk '{print $1}' || echo "1")
|
||||
|
||||
if [ "$tcp_out" -gt 1000000 ]; then
|
||||
local retrans_percent=$(echo "scale=2; $tcp_retrans * 100 / $tcp_out" | bc 2>/dev/null || echo "0")
|
||||
|
||||
if (( $(echo "$retrans_percent > 5" | bc -l 2>/dev/null || echo 0) )); then
|
||||
add_finding "WARNING" "High TCP Retransmission Rate" \
|
||||
"Retransmission rate: ${retrans_percent}%
|
||||
Segments retransmitted: $tcp_retrans
|
||||
Total segments sent: $tcp_out" \
|
||||
"High retransmission indicates network problems:
|
||||
• Test packet loss: ping -c 100 8.8.8.8
|
||||
• Check MTU settings
|
||||
• Review network congestion
|
||||
• Contact hosting provider if persistent"
|
||||
else
|
||||
add_finding "INFO" "TCP Retransmission Rate" \
|
||||
"Retransmission rate: ${retrans_percent}% (healthy)
|
||||
Segments retransmitted: $tcp_retrans
|
||||
Total segments sent: $tcp_out" \
|
||||
"TCP retransmission rate is within normal range"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Test connectivity to common DNS
|
||||
echo -e "${CYAN}[INFO]${NC} Testing network connectivity..."
|
||||
local ping_result=$(ping -c 5 -W 2 8.8.8.8 2>/dev/null | grep "packet loss" | awk '{print $6}' | tr -d '%')
|
||||
|
||||
if [ -n "$ping_result" ]; then
|
||||
if (( $(echo "$ping_result > 5" | bc -l 2>/dev/null || echo 0) )); then
|
||||
add_finding "WARNING" "Packet Loss Detected" \
|
||||
"Packet loss to 8.8.8.8: ${ping_result}%
|
||||
This indicates network connectivity issues" \
|
||||
"Investigate packet loss:
|
||||
• Test multiple targets: ping -c 100 [your-dns-server]
|
||||
• Check for network congestion
|
||||
• Review with hosting provider
|
||||
• Check interface errors (see above)"
|
||||
else
|
||||
local avg_latency=$(ping -c 5 -W 2 8.8.8.8 2>/dev/null | grep "avg" | awk -F'/' '{print $5}')
|
||||
add_finding "INFO" "Network Connectivity Test" \
|
||||
"Packet loss: ${ping_result}% (excellent)
|
||||
Average latency: ${avg_latency}ms" \
|
||||
"Network connectivity is healthy"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to recommend monitoring tools
|
||||
recommend_monitoring_tools() {
|
||||
echo -e "${CYAN}[INFO]${NC} Checking for real-time monitoring tools..."
|
||||
|
||||
local tools_needed=()
|
||||
local tools_installed=()
|
||||
|
||||
# Check iftop
|
||||
if command_exists iftop; then
|
||||
tools_installed+=("iftop - Real-time bandwidth by connection")
|
||||
else
|
||||
tools_needed+=("iftop - Real-time bandwidth monitoring (yum install iftop)")
|
||||
fi
|
||||
|
||||
# Check nethogs
|
||||
if command_exists nethogs; then
|
||||
tools_installed+=("nethogs - Bandwidth by process")
|
||||
else
|
||||
tools_needed+=("nethogs - Per-process bandwidth monitoring (yum install nethogs)")
|
||||
fi
|
||||
|
||||
# Check nload
|
||||
if command_exists nload; then
|
||||
tools_installed+=("nload - Simple real-time traffic graph")
|
||||
else
|
||||
tools_needed+=("nload - Simple bandwidth monitor (yum install nload)")
|
||||
fi
|
||||
|
||||
# Check iperf3
|
||||
if command_exists iperf3; then
|
||||
tools_installed+=("iperf3 - Network performance testing")
|
||||
else
|
||||
tools_needed+=("iperf3 - Bandwidth testing tool (yum install iperf3)")
|
||||
fi
|
||||
|
||||
if [ ${#tools_installed[@]} -gt 0 ]; then
|
||||
local installed_list=$(printf ' • %s\n' "${tools_installed[@]}")
|
||||
add_finding "INFO" "Installed Monitoring Tools" \
|
||||
"$installed_list" \
|
||||
"Use these tools for real-time bandwidth monitoring"
|
||||
fi
|
||||
|
||||
if [ ${#tools_needed[@]} -gt 0 ]; then
|
||||
local needed_list=$(printf ' • %s\n' "${tools_needed[@]}")
|
||||
add_finding "INFO" "Recommended Monitoring Tools" \
|
||||
"Consider installing these tools for better monitoring:
|
||||
$needed_list" \
|
||||
"Install tools: yum install iftop nethogs nload iperf3
|
||||
Usage examples:
|
||||
• iftop -i $interface (real-time bandwidth by connection)
|
||||
• nethogs $interface (bandwidth by process)
|
||||
• nload $interface (simple traffic graph)
|
||||
• vnstat -l (live traffic stats)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to generate report
|
||||
generate_report() {
|
||||
local report_content=""
|
||||
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="NETWORK & BANDWIDTH ANALYSIS - $(date '+%Y-%m-%d %H:%M:%S')"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="System: $SYS_HOSTNAME"$'\n'
|
||||
report_content+="Control Panel: $SYS_PANEL ${SYS_PANEL_VER:-unknown}"$'\n'
|
||||
report_content+="OS: $SYS_OS ${SYS_OS_VER:-unknown}"$'\n'
|
||||
report_content+=""$'\n'
|
||||
|
||||
# Group findings by category
|
||||
local -A categories
|
||||
categories["BANDWIDTH"]=""
|
||||
categories["WEB_TRAFFIC"]=""
|
||||
categories["CONNECTIONS"]=""
|
||||
categories["PERFORMANCE"]=""
|
||||
categories["TOOLS"]=""
|
||||
categories["OTHER"]=""
|
||||
|
||||
for finding in "${FINDINGS[@]}"; do
|
||||
# Split by @@@SEP@@@ delimiter
|
||||
local severity_title="${finding%%@@@SEP@@@*}"
|
||||
local temp="${finding#*@@@SEP@@@}"
|
||||
local details="${temp%%@@@SEP@@@*}"
|
||||
local recommendation="${temp#*@@@SEP@@@}"
|
||||
|
||||
# Extract severity from [SEVERITY] Title format
|
||||
local severity=$(echo "$severity_title" | sed -n 's/^\[\([^]]*\)\].*/\1/p')
|
||||
local title=$(echo "$severity_title" | sed 's/^\[[^]]*\] //')
|
||||
|
||||
local category="OTHER"
|
||||
if [[ "$title" == *"Bandwidth"* ]] || [[ "$title" == *"Monthly"* ]] || [[ "$title" == *"Daily"* ]] || [[ "$title" == *"Hourly"* ]]; then
|
||||
category="BANDWIDTH"
|
||||
elif [[ "$title" == *"Domain"* ]] || [[ "$title" == *"URL"* ]] || [[ "$title" == *"Web"* ]] || [[ "$title" == *"IP"* ]]; then
|
||||
category="WEB_TRAFFIC"
|
||||
elif [[ "$title" == *"Connection"* ]]; then
|
||||
category="CONNECTIONS"
|
||||
elif [[ "$title" == *"Network"* ]] || [[ "$title" == *"TCP"* ]] || [[ "$title" == *"MTU"* ]] || [[ "$title" == *"Packet"* ]]; then
|
||||
category="PERFORMANCE"
|
||||
elif [[ "$title" == *"Tool"* ]] || [[ "$title" == *"Monitoring"* ]]; then
|
||||
category="TOOLS"
|
||||
fi
|
||||
|
||||
local entry=""
|
||||
entry+="[$severity] $title"$'\n'
|
||||
entry+="$details"$'\n'
|
||||
if [ -n "$recommendation" ]; then
|
||||
entry+="Recommendation:"$'\n'
|
||||
entry+="$recommendation"$'\n'
|
||||
fi
|
||||
entry+=""$'\n'
|
||||
entry+="------------------------------------------------------------------------------"$'\n'
|
||||
entry+=""$'\n'
|
||||
|
||||
categories[$category]+="$entry"
|
||||
done
|
||||
|
||||
# Output sections
|
||||
if [ -n "${categories[BANDWIDTH]}" ]; then
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="BANDWIDTH USAGE"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="${categories[BANDWIDTH]}"
|
||||
fi
|
||||
|
||||
if [ -n "${categories[WEB_TRAFFIC]}" ]; then
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="WEB TRAFFIC ANALYSIS"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="${categories[WEB_TRAFFIC]}"
|
||||
fi
|
||||
|
||||
if [ -n "${categories[CONNECTIONS]}" ]; then
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="NETWORK CONNECTIONS"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="${categories[CONNECTIONS]}"
|
||||
fi
|
||||
|
||||
if [ -n "${categories[PERFORMANCE]}" ]; then
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="NETWORK PERFORMANCE"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="${categories[PERFORMANCE]}"
|
||||
fi
|
||||
|
||||
if [ -n "${categories[TOOLS]}" ]; then
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="MONITORING TOOLS"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="${categories[TOOLS]}"
|
||||
fi
|
||||
|
||||
if [ -n "${categories[OTHER]}" ]; then
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="OTHER FINDINGS"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="${categories[OTHER]}"
|
||||
fi
|
||||
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+="NEXT STEPS"$'\n'
|
||||
report_content+="=============================================================================="$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="Priority Actions:"$'\n'
|
||||
report_content+=" 1. Review bandwidth usage trends for unusual patterns"$'\n'
|
||||
report_content+=" 2. Investigate high-volume IP addresses and domains"$'\n'
|
||||
report_content+=" 3. Address any network performance issues"$'\n'
|
||||
report_content+=" 4. Consider installing monitoring tools for real-time tracking"$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="Additional Analysis Available:"$'\n'
|
||||
report_content+=" • Bot Analyzer (Main Menu → Security) for bot/attack traffic analysis"$'\n'
|
||||
report_content+=" • System Health Check (Main Menu) for overall server health"$'\n'
|
||||
report_content+=""$'\n'
|
||||
report_content+="Report saved to: $REPORT_FILE"$'\n'
|
||||
report_content+=""$'\n'
|
||||
|
||||
echo "$report_content"
|
||||
echo "$report_content" > "$REPORT_FILE"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
show_banner
|
||||
echo -e "${BLUE}${BOLD}🌐 Network & Bandwidth Analyzer${NC}"
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
echo -e "${CYAN}[INFO]${NC} Starting network and bandwidth analysis..."
|
||||
echo ""
|
||||
|
||||
# Run analyses
|
||||
analyze_bandwidth_vnstat
|
||||
analyze_web_traffic
|
||||
analyze_network_connections
|
||||
analyze_network_performance
|
||||
recommend_monitoring_tools
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}[OK]${NC} Analysis complete!"
|
||||
echo ""
|
||||
|
||||
# Generate and display report
|
||||
generate_report
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}[INFO]${NC} Full report saved to: ${CYAN}$REPORT_FILE${NC}"
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
press_enter
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main
|
||||
Executable
+3240
File diff suppressed because it is too large
Load Diff
Executable
+368
@@ -0,0 +1,368 @@
|
||||
#!/bin/bash
|
||||
|
||||
################################################################################
|
||||
# cPHulk Enablement Script with CSF Whitelist Import
|
||||
################################################################################
|
||||
# Purpose: Enable cPHulk brute force protection and import CSF allowed IPs
|
||||
# Requirements: cPanel server with CSF installed
|
||||
# Author: Server Toolkit
|
||||
#
|
||||
# IMPORTANT NOTES:
|
||||
# - cPHulk operates SYSTEM-WIDE (not per-user or per-domain)
|
||||
# - Protects all authentication services: cPanel, WHM, SSH, FTP, Email
|
||||
# - This script intelligently discovers ALL CSF whitelist files including:
|
||||
# * Standard files (/etc/csf/csf.allow, cpanel.allow, etc.)
|
||||
# * Include directives (follows recursively)
|
||||
# * Hosting panel integrations (LiquidWeb, cPanel, InterWorx, etc.)
|
||||
# * Custom locations configured in csf.conf
|
||||
# - Supports multiple IP formats: simple IPs, s=IP, d=IP, CIDR notation
|
||||
################################################################################
|
||||
|
||||
# Get script directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
source "$SCRIPT_DIR/lib/common-functions.sh"
|
||||
source "$SCRIPT_DIR/lib/system-detect.sh"
|
||||
|
||||
# Require root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
print_error "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_banner "cPHulk Enablement with CSF Whitelist Import"
|
||||
|
||||
# Check if cPanel
|
||||
if [ "$SYS_CONTROL_PANEL" != "cpanel" ]; then
|
||||
print_error "This script is for cPanel servers only"
|
||||
print_info "Detected control panel: ${SYS_CONTROL_PANEL:-none}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if cPHulk exists
|
||||
if [ ! -x "/usr/local/cpanel/bin/cphulk_pam_ctl" ]; then
|
||||
print_error "cPHulk not found. This may not be a standard cPanel installation."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if CSF is installed
|
||||
if [ ! -x "/usr/sbin/csf" ]; then
|
||||
print_warning "CSF not found - will skip CSF whitelist import"
|
||||
CSF_AVAILABLE=false
|
||||
else
|
||||
CSF_AVAILABLE=true
|
||||
fi
|
||||
|
||||
print_section "Current cPHulk Status"
|
||||
|
||||
# Get current status
|
||||
CPHULK_STATUS=$(/usr/local/cpanel/bin/cphulk_pam_ctl --status 2>/dev/null)
|
||||
if echo "$CPHULK_STATUS" | grep -qi "enabled"; then
|
||||
print_success "cPHulk is currently ENABLED"
|
||||
ALREADY_ENABLED=true
|
||||
else
|
||||
print_info "cPHulk is currently DISABLED"
|
||||
ALREADY_ENABLED=false
|
||||
fi
|
||||
|
||||
# Show current whitelist count
|
||||
CURRENT_WHITELIST=$(/usr/local/cpanel/scripts/cphulkdwhitelist --list 2>/dev/null | grep -v "^$" | wc -l)
|
||||
print_info "Current cPHulk whitelist entries: $CURRENT_WHITELIST"
|
||||
|
||||
if [ "$CSF_AVAILABLE" = true ]; then
|
||||
print_section "CSF Whitelist Analysis"
|
||||
|
||||
# Get CSF allowed IPs
|
||||
echo "Scanning CSF allow files and following Include directives..."
|
||||
echo ""
|
||||
|
||||
# Start with main CSF allow file and follow all includes recursively
|
||||
declare -A PROCESSED_FILES # Track processed files to avoid duplicates
|
||||
CSF_FILES=()
|
||||
|
||||
# Function to recursively find included files
|
||||
find_csf_files() {
|
||||
local current_file="$1"
|
||||
|
||||
# Skip if already processed or doesn't exist
|
||||
[ -n "${PROCESSED_FILES[$current_file]}" ] && return
|
||||
[ ! -f "$current_file" ] && return
|
||||
|
||||
# Mark as processed
|
||||
PROCESSED_FILES["$current_file"]=1
|
||||
CSF_FILES+=("$current_file")
|
||||
|
||||
# Look for Include directives
|
||||
while IFS= read -r line; do
|
||||
if [[ "$line" =~ ^Include[[:space:]]+(.+)$ ]]; then
|
||||
local included_file="${BASH_REMATCH[1]}"
|
||||
# Trim whitespace
|
||||
included_file=$(echo "$included_file" | xargs)
|
||||
# Recursively process included file
|
||||
find_csf_files "$included_file"
|
||||
fi
|
||||
done < "$current_file"
|
||||
}
|
||||
|
||||
# Method 1: Start with main csf.allow and follow all includes
|
||||
if [ -f "/etc/csf/csf.allow" ]; then
|
||||
find_csf_files "/etc/csf/csf.allow"
|
||||
fi
|
||||
|
||||
# Method 2: Scan for all .allow files in /etc/csf/ (catches files not included)
|
||||
while IFS= read -r file; do
|
||||
find_csf_files "$file"
|
||||
done < <(find /etc/csf/ -maxdepth 1 -type f -name "*.allow" 2>/dev/null)
|
||||
|
||||
# Method 3: Check csf.conf for ALLOWIPS_INCLUDE directive
|
||||
# This directive can point to custom include directories
|
||||
if [ -f "/etc/csf/csf.conf" ]; then
|
||||
ALLOWIPS_INCLUDE=$(grep "^ALLOWIPS_INCLUDE" /etc/csf/csf.conf | cut -d'=' -f2 | tr -d '"' | tr -d ' ')
|
||||
if [ -n "$ALLOWIPS_INCLUDE" ] && [ -d "$ALLOWIPS_INCLUDE" ]; then
|
||||
echo "Found ALLOWIPS_INCLUDE directory: $ALLOWIPS_INCLUDE"
|
||||
while IFS= read -r file; do
|
||||
find_csf_files "$file"
|
||||
done < <(find "$ALLOWIPS_INCLUDE" -type f 2>/dev/null)
|
||||
fi
|
||||
fi
|
||||
|
||||
# Method 4: Common custom CSF include locations (hosting panel integrations)
|
||||
COMMON_CSF_LOCATIONS=(
|
||||
"/usr/local/lp/etc/csf" # LiquidWeb
|
||||
"/usr/local/cpanel/etc/csf" # cPanel custom
|
||||
"/usr/local/interworx/etc/csf" # InterWorx
|
||||
"/var/cpanel/csf" # cPanel var
|
||||
"/root/.csf" # Custom user location
|
||||
)
|
||||
|
||||
for location in "${COMMON_CSF_LOCATIONS[@]}"; do
|
||||
if [ -d "$location" ]; then
|
||||
# Look for all .allow files in these locations
|
||||
while IFS= read -r file; do
|
||||
find_csf_files "$file"
|
||||
done < <(find "$location" -type f -name "*allow*" 2>/dev/null)
|
||||
fi
|
||||
done
|
||||
|
||||
# Method 5: Parse all Include directives from csf.conf CUSTOM variables
|
||||
if [ -f "/etc/csf/csf.conf" ]; then
|
||||
# Some systems use CUSTOM1_LOG through CUSTOM9_LOG which may reference allow files
|
||||
while IFS= read -r include_path; do
|
||||
if [ -f "$include_path" ]; then
|
||||
find_csf_files "$include_path"
|
||||
fi
|
||||
done < <(grep -E "^(CUSTOM|GENERIC).*Include" /etc/csf/csf.conf 2>/dev/null | grep -oE '\/[^"]+' || true)
|
||||
fi
|
||||
|
||||
if [ ${#CSF_FILES[@]} -eq 0 ]; then
|
||||
print_warning "No CSF .allow files found"
|
||||
CSF_AVAILABLE=false
|
||||
else
|
||||
echo "Found ${#CSF_FILES[@]} CSF allow files (including includes):"
|
||||
for file in "${CSF_FILES[@]}"; do
|
||||
if [[ "$file" == /etc/csf/* ]]; then
|
||||
echo " • $(basename "$file")"
|
||||
else
|
||||
echo " • $file"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Extract IPs from all CSF files
|
||||
CSF_ALLOW_IPS=()
|
||||
declare -A IP_SOURCE_COUNT # Track which files contributed IPs
|
||||
|
||||
if [ ${#CSF_FILES[@]} -gt 0 ]; then
|
||||
for csf_file in "${CSF_FILES[@]}"; do
|
||||
file_ip_count=0
|
||||
file_display_name=""
|
||||
|
||||
if [[ "$csf_file" == /etc/csf/* ]]; then
|
||||
file_display_name="$(basename "$csf_file")"
|
||||
else
|
||||
file_display_name="$csf_file"
|
||||
fi
|
||||
|
||||
while IFS= read -r line; do
|
||||
# Skip comments and empty lines
|
||||
[[ "$line" =~ ^#.*$ ]] && continue
|
||||
[[ -z "$line" ]] && continue
|
||||
|
||||
# Skip Include directives (already processed)
|
||||
[[ "$line" =~ ^Include ]] && continue
|
||||
|
||||
# Try multiple IP extraction methods:
|
||||
ip=""
|
||||
|
||||
# Method 1: Simple IP format (IP at start of line)
|
||||
# Example: 192.168.100.1 # comment
|
||||
# Also handles CIDR: 10.20.4.0/22 # comment (strip /CIDR, just get IP)
|
||||
if [ -z "$ip" ]; then
|
||||
ip=$(echo "$line" | awk '{print $1}' | grep -oE '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
|
||||
fi
|
||||
|
||||
# Method 2: CSF source format (s=IP)
|
||||
# Example: tcp|in|d=4|s=208.74.123.2 # cPanel Auth Server
|
||||
if [ -z "$ip" ]; then
|
||||
ip=$(echo "$line" | grep -oE 's=[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | cut -d'=' -f2)
|
||||
fi
|
||||
|
||||
# Method 3: CSF destination format (d=IP)
|
||||
# Example: tcp|out|d=443|d=45.11.128.61/32
|
||||
if [ -z "$ip" ]; then
|
||||
# Extract last d= parameter that contains an IP (not a port)
|
||||
ip=$(echo "$line" | grep -oE 'd=[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | tail -1 | cut -d'=' -f2)
|
||||
fi
|
||||
|
||||
if [ -n "$ip" ]; then
|
||||
# Check if not already in array (deduplicate)
|
||||
if [[ ! " ${CSF_ALLOW_IPS[@]} " =~ " ${ip} " ]]; then
|
||||
CSF_ALLOW_IPS+=("$ip")
|
||||
file_ip_count=$((file_ip_count + 1))
|
||||
fi
|
||||
fi
|
||||
done < "$csf_file"
|
||||
|
||||
# Track count per file
|
||||
if [ $file_ip_count -gt 0 ]; then
|
||||
IP_SOURCE_COUNT["$file_display_name"]=$file_ip_count
|
||||
fi
|
||||
done
|
||||
|
||||
# Show breakdown by file
|
||||
echo "IP breakdown by source file:"
|
||||
for file in $(printf '%s\n' "${!IP_SOURCE_COUNT[@]}" | sort); do
|
||||
printf " • %-45s %3d IPs\n" "$file" "${IP_SOURCE_COUNT[$file]}"
|
||||
done
|
||||
echo ""
|
||||
|
||||
print_success "Found ${#CSF_ALLOW_IPS[@]} total unique IPs across all CSF files"
|
||||
fi
|
||||
|
||||
if [ ${#CSF_ALLOW_IPS[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
echo "Sample IPs to be imported:"
|
||||
for i in {0..4}; do
|
||||
if [ -n "${CSF_ALLOW_IPS[$i]}" ]; then
|
||||
echo " • ${CSF_ALLOW_IPS[$i]}"
|
||||
fi
|
||||
done
|
||||
if [ ${#CSF_ALLOW_IPS[@]} -gt 5 ]; then
|
||||
echo " ... and $((${#CSF_ALLOW_IPS[@]} - 5)) more"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_section "Actions to Perform"
|
||||
|
||||
if [ "$ALREADY_ENABLED" = false ]; then
|
||||
echo " 1. Enable cPHulk brute force protection"
|
||||
else
|
||||
echo " 1. cPHulk already enabled (skip)"
|
||||
fi
|
||||
|
||||
if [ "$CSF_AVAILABLE" = true ] && [ ${#CSF_ALLOW_IPS[@]} -gt 0 ]; then
|
||||
echo " 2. Import ${#CSF_ALLOW_IPS[@]} IPs from CSF to cPHulk whitelist"
|
||||
else
|
||||
echo " 2. No CSF IPs to import (skip)"
|
||||
fi
|
||||
|
||||
echo " 3. Display final configuration"
|
||||
|
||||
echo ""
|
||||
read -p "Proceed with these actions? (yes/no): " confirm
|
||||
|
||||
if [ "$confirm" != "yes" ]; then
|
||||
print_info "Operation cancelled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
print_section "Execution"
|
||||
|
||||
# Step 1: Enable cPHulk
|
||||
if [ "$ALREADY_ENABLED" = false ]; then
|
||||
print_info "Enabling cPHulk..."
|
||||
if /usr/local/cpanel/bin/cphulk_pam_ctl --enable 2>&1; then
|
||||
print_success "cPHulk enabled successfully"
|
||||
else
|
||||
print_error "Failed to enable cPHulk"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
print_info "cPHulk already enabled, skipping"
|
||||
fi
|
||||
|
||||
# Step 2: Import CSF whitelist
|
||||
if [ "$CSF_AVAILABLE" = true ] && [ ${#CSF_ALLOW_IPS[@]} -gt 0 ]; then
|
||||
print_info "Importing CSF whitelist to cPHulk..."
|
||||
|
||||
IMPORTED=0
|
||||
SKIPPED=0
|
||||
FAILED=0
|
||||
|
||||
for ip in "${CSF_ALLOW_IPS[@]}"; do
|
||||
# Check if already in cPHulk whitelist
|
||||
if /usr/local/cpanel/scripts/cphulkdwhitelist --list 2>/dev/null | grep -q "$ip"; then
|
||||
SKIPPED=$((SKIPPED + 1))
|
||||
echo " [SKIP] $ip (already whitelisted)"
|
||||
else
|
||||
# Add to cPHulk whitelist
|
||||
if whmapi1 cphulkd_add_whitelist ip="$ip" 2>&1 | grep -q "success.*1"; then
|
||||
IMPORTED=$((IMPORTED + 1))
|
||||
echo " [OK] $ip"
|
||||
else
|
||||
FAILED=$((FAILED + 1))
|
||||
echo " [FAIL] $ip"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
print_success "Import complete:"
|
||||
echo " • Imported: $IMPORTED"
|
||||
echo " • Skipped (already whitelisted): $SKIPPED"
|
||||
if [ $FAILED -gt 0 ]; then
|
||||
print_warning "Failed: $FAILED"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Step 3: Display final status
|
||||
echo ""
|
||||
print_section "Final Configuration"
|
||||
|
||||
# Check status
|
||||
FINAL_STATUS=$(/usr/local/cpanel/bin/cphulk_pam_ctl --status 2>/dev/null)
|
||||
if echo "$FINAL_STATUS" | grep -qi "enabled"; then
|
||||
print_success "cPHulk Status: ENABLED"
|
||||
else
|
||||
print_error "cPHulk Status: DISABLED (unexpected)"
|
||||
fi
|
||||
|
||||
# Count whitelist
|
||||
FINAL_WHITELIST=$(/usr/local/cpanel/scripts/cphulkdwhitelist --list 2>/dev/null | grep -v "^$" | wc -l)
|
||||
print_info "cPHulk whitelist entries: $FINAL_WHITELIST"
|
||||
|
||||
echo ""
|
||||
print_section "Next Steps"
|
||||
|
||||
echo "1. Configure cPHulk settings in WHM:"
|
||||
echo " WHM → Security Center → cPHulk Brute Force Protection"
|
||||
echo ""
|
||||
echo "2. Recommended settings:"
|
||||
echo " • Brute Force Protection Period: 5 minutes"
|
||||
echo " • Maximum Failures per Account: 5"
|
||||
echo " • Maximum Failures per IP: 10"
|
||||
echo ""
|
||||
echo "3. Add your own IPs to whitelist:"
|
||||
echo " whmapi1 cphulkd_add_whitelist ip=YOUR.IP.ADDRESS"
|
||||
echo ""
|
||||
echo "4. View currently blocked IPs:"
|
||||
echo " whmapi1 cphulkd_list_blocks"
|
||||
echo ""
|
||||
echo "5. Remove a blocked IP:"
|
||||
echo " whmapi1 cphulkd_remove_block ip=IP.TO.UNBLOCK"
|
||||
|
||||
echo ""
|
||||
print_success "cPHulk setup complete!"
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
source "$SCRIPT_DIR/lib/common-functions.sh"
|
||||
print_banner "Firewall Activity Monitor"
|
||||
echo "Monitoring CSF/iptables activity..."
|
||||
echo "Press Ctrl+C to exit"
|
||||
echo ""
|
||||
tail -f /var/log/messages | grep --line-buffered -i "iptables\|csf\|firewall"
|
||||
Executable
+402
@@ -0,0 +1,402 @@
|
||||
#!/bin/bash
|
||||
|
||||
################################################################################
|
||||
# Live Network Security Monitor
|
||||
################################################################################
|
||||
# Purpose: Real-time monitoring of active attacks and suspicious traffic
|
||||
# Use Case: When server is currently under attack, monitor all activity live
|
||||
# Author: Server Toolkit
|
||||
#
|
||||
# FEATURES:
|
||||
# - Multi-source monitoring (SSH, Web, Email, Firewall)
|
||||
# - Real-time threat detection and classification
|
||||
# - Color-coded alerts (Critical/High/Medium/Low)
|
||||
# - Live statistics dashboard
|
||||
# - Connection tracking and blocking suggestions
|
||||
# - Attack pattern recognition
|
||||
################################################################################
|
||||
|
||||
# Get script directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
source "$SCRIPT_DIR/lib/common-functions.sh"
|
||||
source "$SCRIPT_DIR/lib/system-detect.sh"
|
||||
|
||||
# Require root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
print_error "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Color definitions for threat levels
|
||||
CRITICAL_COLOR='\033[1;41;97m' # White on Red background
|
||||
HIGH_COLOR='\033[1;31m' # Bold Red
|
||||
MEDIUM_COLOR='\033[1;33m' # Bold Yellow
|
||||
LOW_COLOR='\033[0;36m' # Cyan
|
||||
INFO_COLOR='\033[0;37m' # White
|
||||
NC='\033[0m'
|
||||
|
||||
# Configuration
|
||||
REFRESH_INTERVAL=2 # Seconds between dashboard refreshes
|
||||
MAX_DISPLAY_LINES=30
|
||||
THREAT_THRESHOLD_HIGH=10 # Requests per second from single IP
|
||||
THREAT_THRESHOLD_MEDIUM=5
|
||||
|
||||
# Temporary files for tracking - use fixed directory for subshell access
|
||||
TEMP_DIR="/tmp/live-monitor-current"
|
||||
rm -rf "$TEMP_DIR" 2>/dev/null # Clean any previous session
|
||||
mkdir -p "$TEMP_DIR"
|
||||
touch "$TEMP_DIR/recent_events"
|
||||
|
||||
# Cleanup function to kill all child processes
|
||||
cleanup() {
|
||||
echo ""
|
||||
echo "Stopping monitoring processes..."
|
||||
|
||||
# Kill all processes in this process group
|
||||
kill $(jobs -p) 2>/dev/null
|
||||
|
||||
# Also kill any stray tail processes monitoring our logs
|
||||
pkill -P $$ 2>/dev/null
|
||||
|
||||
# Clean up temp directory
|
||||
rm -rf "$TEMP_DIR" 2>/dev/null
|
||||
|
||||
# Restore cursor
|
||||
tput cnorm
|
||||
|
||||
echo "✓ Cleanup complete"
|
||||
exit 0
|
||||
}
|
||||
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# Statistics counters
|
||||
declare -A IP_COUNTER
|
||||
declare -A IP_THREAT_LEVEL
|
||||
declare -A ATTACK_TYPE_COUNTER
|
||||
declare -A BLOCKED_IPS
|
||||
TOTAL_EVENTS=0
|
||||
TOTAL_THREATS=0
|
||||
START_TIME=$(date +%s)
|
||||
|
||||
# Hide cursor for cleaner display
|
||||
tput civis
|
||||
|
||||
################################################################################
|
||||
# Threat Classification Functions
|
||||
################################################################################
|
||||
|
||||
classify_threat_level() {
|
||||
local count="$1"
|
||||
|
||||
if [ "$count" -ge "$THREAT_THRESHOLD_HIGH" ]; then
|
||||
echo "CRITICAL"
|
||||
elif [ "$count" -ge "$THREAT_THRESHOLD_MEDIUM" ]; then
|
||||
echo "HIGH"
|
||||
else
|
||||
echo "MEDIUM"
|
||||
fi
|
||||
}
|
||||
|
||||
get_threat_color() {
|
||||
local level="$1"
|
||||
|
||||
case "$level" in
|
||||
CRITICAL) echo "$CRITICAL_COLOR" ;;
|
||||
HIGH) echo "$HIGH_COLOR" ;;
|
||||
MEDIUM) echo "$MEDIUM_COLOR" ;;
|
||||
LOW) echo "$LOW_COLOR" ;;
|
||||
*) echo "$INFO_COLOR" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
identify_attack_type() {
|
||||
local log_line="$1"
|
||||
|
||||
# SSH brute force
|
||||
if echo "$log_line" | grep -qi "Failed password\|authentication failure"; then
|
||||
echo "SSH_BRUTEFORCE"
|
||||
# SQL injection attempts
|
||||
elif echo "$log_line" | grep -qiE "union.*select|concat.*\(|substring.*\(|' or '1'='1"; then
|
||||
echo "SQL_INJECTION"
|
||||
# XSS attempts
|
||||
elif echo "$log_line" | grep -qiE "<script|javascript:|onerror=|onload="; then
|
||||
echo "XSS_ATTACK"
|
||||
# Path traversal
|
||||
elif echo "$log_line" | grep -qE "\.\./|\.\.%2[fF]"; then
|
||||
echo "PATH_TRAVERSAL"
|
||||
# Port scanning
|
||||
elif echo "$log_line" | grep -qi "port scan\|SYN_RECV"; then
|
||||
echo "PORT_SCAN"
|
||||
# Directory enumeration
|
||||
elif echo "$log_line" | grep -qE "404.*\.(php|asp|jsp|cgi)"; then
|
||||
echo "DIR_ENUM"
|
||||
# Bot/crawler
|
||||
elif echo "$log_line" | grep -qiE "bot|crawler|spider|scraper"; then
|
||||
echo "BOT"
|
||||
# DDoS patterns
|
||||
elif echo "$log_line" | grep -qi "SYN flood\|UDP flood"; then
|
||||
echo "DDOS"
|
||||
# Exploit attempts
|
||||
elif echo "$log_line" | grep -qiE "exploit|shell|backdoor|webshell"; then
|
||||
echo "EXPLOIT"
|
||||
# Excessive requests (likely DDoS or bot)
|
||||
else
|
||||
echo "SUSPICIOUS"
|
||||
fi
|
||||
}
|
||||
|
||||
get_attack_icon() {
|
||||
local attack_type="$1"
|
||||
|
||||
case "$attack_type" in
|
||||
SSH_BRUTEFORCE) echo "🔐" ;;
|
||||
SQL_INJECTION) echo "💉" ;;
|
||||
XSS_ATTACK) echo "⚠️ " ;;
|
||||
PATH_TRAVERSAL) echo "📁" ;;
|
||||
PORT_SCAN) echo "🔍" ;;
|
||||
DIR_ENUM) echo "📂" ;;
|
||||
BOT) echo "🤖" ;;
|
||||
DDOS) echo "💥" ;;
|
||||
EXPLOIT) echo "☠️ " ;;
|
||||
*) echo "❓" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Dashboard Display Functions
|
||||
################################################################################
|
||||
|
||||
draw_header() {
|
||||
clear
|
||||
local uptime=$(($(date +%s) - START_TIME))
|
||||
local uptime_str=$(printf "%02d:%02d:%02d" $((uptime/3600)) $((uptime%3600/60)) $((uptime%60)))
|
||||
|
||||
echo -e "${CRITICAL_COLOR}╔════════════════════════════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${CRITICAL_COLOR}║ 🚨 LIVE NETWORK SECURITY MONITOR 🚨 ║${NC}"
|
||||
echo -e "${CRITICAL_COLOR}╚════════════════════════════════════════════════════════════════════════════╝${NC}"
|
||||
echo -e "${INFO_COLOR}Runtime: ${uptime_str} | Events: ${TOTAL_EVENTS} | Threats Detected: ${TOTAL_THREATS} | Monitoring...${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
draw_statistics_panel() {
|
||||
echo -e "${HIGH_COLOR}┌─ THREAT STATISTICS ────────────────────────────────────────────────────────┐${NC}"
|
||||
|
||||
# Top attacking IPs
|
||||
echo -e "${MEDIUM_COLOR}Top Attacking IPs:${NC}"
|
||||
local count=0
|
||||
for ip in "${!IP_COUNTER[@]}"; do
|
||||
local hits="${IP_COUNTER[$ip]}"
|
||||
local level="${IP_THREAT_LEVEL[$ip]:-MEDIUM}"
|
||||
local color=$(get_threat_color "$level")
|
||||
|
||||
printf "${color} %-15s %5d hits [%s]${NC}\n" "$ip" "$hits" "$level"
|
||||
|
||||
((count++))
|
||||
[ $count -ge 5 ] && break
|
||||
done | sort -t' ' -k2 -rn
|
||||
|
||||
echo ""
|
||||
|
||||
# Attack type breakdown
|
||||
echo -e "${MEDIUM_COLOR}Attack Type Distribution:${NC}"
|
||||
for attack_type in "${!ATTACK_TYPE_COUNTER[@]}"; do
|
||||
local count="${ATTACK_TYPE_COUNTER[$attack_type]}"
|
||||
local icon=$(get_attack_icon "$attack_type")
|
||||
printf " ${icon} %-20s %5d\n" "$attack_type" "$count"
|
||||
done | sort -t' ' -k3 -rn | head -5
|
||||
|
||||
echo -e "${HIGH_COLOR}└────────────────────────────────────────────────────────────────────────────┘${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
draw_live_feed() {
|
||||
echo -e "${HIGH_COLOR}┌─ LIVE THREAT FEED ─────────────────────────────────────────────────────────┐${NC}"
|
||||
|
||||
if [ -f "$TEMP_DIR/recent_events" ]; then
|
||||
tail -n "$MAX_DISPLAY_LINES" "$TEMP_DIR/recent_events"
|
||||
else
|
||||
echo -e "${LOW_COLOR} Waiting for events...${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${HIGH_COLOR}└────────────────────────────────────────────────────────────────────────────┘${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
draw_action_suggestions() {
|
||||
echo -e "${MEDIUM_COLOR}┌─ SUGGESTED ACTIONS ────────────────────────────────────────────────────────┐${NC}"
|
||||
|
||||
# Suggest blocking top attackers
|
||||
local suggested=0
|
||||
for ip in "${!IP_COUNTER[@]}"; do
|
||||
local hits="${IP_COUNTER[$ip]}"
|
||||
local level="${IP_THREAT_LEVEL[$ip]}"
|
||||
|
||||
if [ "$level" = "CRITICAL" ] && [ -z "${BLOCKED_IPS[$ip]}" ]; then
|
||||
echo -e " ${CRITICAL_COLOR}▶${NC} Block IP immediately: ${HIGH_COLOR}csf -d $ip${NC}"
|
||||
((suggested++))
|
||||
[ $suggested -ge 3 ] && break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $suggested -eq 0 ]; then
|
||||
echo -e "${LOW_COLOR} No immediate actions required at this time${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${MEDIUM_COLOR}└────────────────────────────────────────────────────────────────────────────┘${NC}"
|
||||
echo ""
|
||||
echo -e "${INFO_COLOR}Press Ctrl+C to exit | Updates every ${REFRESH_INTERVAL}s${NC}"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Log Monitoring Functions
|
||||
################################################################################
|
||||
|
||||
monitor_ssh_attacks() {
|
||||
# Monitor SSH brute force attempts
|
||||
if [ -f "/var/log/secure" ]; then
|
||||
tail -n 0 -F /var/log/secure 2>/dev/null | while read -r line; do
|
||||
if echo "$line" | grep -qi "Failed password\|authentication failure"; then
|
||||
local ip=$(echo "$line" | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | head -1)
|
||||
if [ -n "$ip" ]; then
|
||||
process_threat_event "$ip" "SSH_BRUTEFORCE" "$line"
|
||||
fi
|
||||
fi
|
||||
done &
|
||||
fi
|
||||
}
|
||||
|
||||
monitor_web_attacks() {
|
||||
# Monitor Apache access logs for web attacks
|
||||
local access_log="/var/log/apache2/domlogs/*"
|
||||
|
||||
if ls $access_log >/dev/null 2>&1; then
|
||||
tail -n 0 -F $access_log 2>/dev/null | while read -r line; do
|
||||
local ip=$(echo "$line" | awk '{print $1}')
|
||||
local request=$(echo "$line" | awk '{print $7}')
|
||||
|
||||
# Check for suspicious patterns
|
||||
if echo "$line" | grep -qiE "union.*select|<script|\.\.\/|\' or |exec\("; then
|
||||
local attack_type=$(identify_attack_type "$line")
|
||||
process_threat_event "$ip" "$attack_type" "$request"
|
||||
# Track high-frequency requests (potential DDoS)
|
||||
elif [ -n "$ip" ]; then
|
||||
((IP_COUNTER[$ip]++))
|
||||
if [ "${IP_COUNTER[$ip]}" -gt "$THREAT_THRESHOLD_MEDIUM" ]; then
|
||||
process_threat_event "$ip" "HIGH_FREQUENCY" "$request"
|
||||
fi
|
||||
fi
|
||||
done &
|
||||
fi
|
||||
}
|
||||
|
||||
monitor_firewall_blocks() {
|
||||
# Monitor CSF/iptables blocks in real-time
|
||||
if [ -f "/var/log/messages" ]; then
|
||||
tail -n 0 -F /var/log/messages 2>/dev/null | while read -r line; do
|
||||
if echo "$line" | grep -qi "Firewall\|iptables\|DENY"; then
|
||||
local ip=$(echo "$line" | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | head -1)
|
||||
if [ -n "$ip" ]; then
|
||||
BLOCKED_IPS[$ip]=1
|
||||
log_event "$ip" "FIREWALL_BLOCK" "${LOW_COLOR}" "Blocked by firewall"
|
||||
fi
|
||||
fi
|
||||
done &
|
||||
fi
|
||||
}
|
||||
|
||||
monitor_cphulk_blocks() {
|
||||
# Monitor cPHulk blocks
|
||||
if [ -x "/usr/local/cpanel/bin/cphulk_pam_ctl" ]; then
|
||||
# Poll cPHulk status periodically
|
||||
while true; do
|
||||
whmapi1 cphulkd_list_blocks 2>/dev/null | grep -E "ip:" | while read -r line; do
|
||||
local ip=$(echo "$line" | awk '{print $2}')
|
||||
if [ -n "$ip" ] && [ -z "${BLOCKED_IPS[$ip]}" ]; then
|
||||
BLOCKED_IPS[$ip]=1
|
||||
log_event "$ip" "CPHULK_BLOCK" "${MEDIUM_COLOR}" "Blocked by cPHulk"
|
||||
fi
|
||||
done
|
||||
sleep 5
|
||||
done &
|
||||
fi
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Event Processing
|
||||
################################################################################
|
||||
|
||||
process_threat_event() {
|
||||
local ip="$1"
|
||||
local attack_type="$2"
|
||||
local details="$3"
|
||||
|
||||
# Update counters
|
||||
((IP_COUNTER[$ip]++))
|
||||
((ATTACK_TYPE_COUNTER[$attack_type]++))
|
||||
((TOTAL_EVENTS++))
|
||||
((TOTAL_THREATS++))
|
||||
|
||||
# Classify threat level
|
||||
local threat_level=$(classify_threat_level "${IP_COUNTER[$ip]}")
|
||||
IP_THREAT_LEVEL[$ip]="$threat_level"
|
||||
|
||||
# Log to feed
|
||||
log_event "$ip" "$attack_type" "$(get_threat_color "$threat_level")" "$details"
|
||||
}
|
||||
|
||||
log_event() {
|
||||
local ip="$1"
|
||||
local attack_type="$2"
|
||||
local color="$3"
|
||||
local details="$4"
|
||||
|
||||
local timestamp=$(date '+%H:%M:%S')
|
||||
local icon=$(get_attack_icon "$attack_type")
|
||||
local hits="${IP_COUNTER[$ip]:-1}"
|
||||
|
||||
# Truncate details if too long
|
||||
details=$(echo "$details" | cut -c1-60)
|
||||
|
||||
# Format: [TIME] ICON IP (hits) - TYPE - details
|
||||
printf "${color}[%s] %s %-15s (%3d) %-20s %s${NC}\n" \
|
||||
"$timestamp" "$icon" "$ip" "$hits" "$attack_type" "$details" \
|
||||
>> "$TEMP_DIR/recent_events"
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Main Monitoring Loop
|
||||
################################################################################
|
||||
|
||||
main() {
|
||||
print_banner "Live Network Security Monitor"
|
||||
|
||||
echo ""
|
||||
echo "Starting multi-source threat monitoring..."
|
||||
echo " • SSH brute force detection"
|
||||
echo " • Web attack detection (SQL, XSS, etc.)"
|
||||
echo " • Firewall block monitoring"
|
||||
echo " • cPHulk activity monitoring"
|
||||
echo ""
|
||||
echo "Press Ctrl+C to stop..."
|
||||
sleep 3
|
||||
|
||||
# Start all monitoring processes
|
||||
monitor_ssh_attacks
|
||||
monitor_web_attacks
|
||||
monitor_firewall_blocks
|
||||
monitor_cphulk_blocks
|
||||
|
||||
# Main display loop
|
||||
while true; do
|
||||
draw_header
|
||||
draw_statistics_panel
|
||||
draw_live_feed
|
||||
draw_action_suggestions
|
||||
|
||||
sleep "$REFRESH_INTERVAL"
|
||||
done
|
||||
}
|
||||
|
||||
# Run main
|
||||
main
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
source "$SCRIPT_DIR/lib/common-functions.sh"
|
||||
|
||||
print_banner "SSH Attack Monitor"
|
||||
echo ""
|
||||
echo "Monitoring SSH authentication attempts in real-time..."
|
||||
echo "Press Ctrl+C to exit"
|
||||
echo ""
|
||||
|
||||
tail -f /var/log/secure | grep --line-buffered -i "failed\|authentication failure" | while read line; do
|
||||
timestamp=$(echo "$line" | awk '{print $1, $2, $3}')
|
||||
ip=$(echo "$line" | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | head -1)
|
||||
printf "[%s] \033[1;31m%-15s\033[0m %s\n" "$timestamp" "$ip" "$(echo $line | cut -c50-)"
|
||||
done
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
source "$SCRIPT_DIR/lib/common-functions.sh"
|
||||
print_banner "Apache Access Log"
|
||||
echo "Tailing Apache access logs..."
|
||||
echo "Press Ctrl+C to exit"
|
||||
echo ""
|
||||
[ -d "/var/log/apache2/domlogs" ] && tail -f /var/log/apache2/domlogs/* || echo "No access logs found"
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
source "$SCRIPT_DIR/lib/common-functions.sh"
|
||||
print_banner "Apache Error Log"
|
||||
echo "Tailing Apache error logs..."
|
||||
echo "Press Ctrl+C to exit"
|
||||
echo ""
|
||||
tail -f /var/log/apache2/error_log 2>/dev/null || tail -f /var/log/httpd/error_log 2>/dev/null || echo "No error logs found"
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
source "$SCRIPT_DIR/lib/common-functions.sh"
|
||||
print_banner "Mail Log Monitor"
|
||||
echo "Tailing mail logs..."
|
||||
echo "Press Ctrl+C to exit"
|
||||
echo ""
|
||||
tail -f /var/log/maillog 2>/dev/null || tail -f /var/log/mail.log 2>/dev/null || echo "No mail logs found"
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
source "$SCRIPT_DIR/lib/common-functions.sh"
|
||||
print_banner "Security Log Monitor"
|
||||
echo "Tailing /var/log/secure..."
|
||||
echo "Press Ctrl+C to exit"
|
||||
echo ""
|
||||
tail -f /var/log/secure
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/bin/bash
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
source "$SCRIPT_DIR/lib/common-functions.sh"
|
||||
|
||||
print_banner "Web Traffic Monitor"
|
||||
echo ""
|
||||
echo "Monitoring Apache access logs in real-time..."
|
||||
echo "Press Ctrl+C to exit"
|
||||
echo ""
|
||||
|
||||
# Find apache log directory
|
||||
if [ -d "/var/log/apache2/domlogs" ]; then
|
||||
tail -f /var/log/apache2/domlogs/* 2>/dev/null | while read line; do
|
||||
ip=$(echo "$line" | awk '{print $1}')
|
||||
request=$(echo "$line" | awk '{print $6, $7}' | tr -d '"')
|
||||
status=$(echo "$line" | awk '{print $9}')
|
||||
|
||||
# Color code by status
|
||||
if [[ "$status" =~ ^5 ]]; then
|
||||
color="\033[1;31m" # Red for 5xx
|
||||
elif [[ "$status" =~ ^4 ]]; then
|
||||
color="\033[1;33m" # Yellow for 4xx
|
||||
elif [[ "$status" =~ ^2 ]]; then
|
||||
color="\033[0;32m" # Green for 2xx
|
||||
else
|
||||
color="\033[0;37m" # White for others
|
||||
fi
|
||||
|
||||
printf "${color}%-15s %s %s\033[0m\n" "$ip" "$status" "$request"
|
||||
done
|
||||
else
|
||||
print_error "Apache domlogs directory not found"
|
||||
fi
|
||||
Reference in New Issue
Block a user