#!/bin/bash # maravento.com # ################################################################################ # # SQUID ANALYSIS TOOL # squidtool.sh # # This script provides a unified interface for analyzing Squid proxy logs. # It contains six main functions: # # 1) squid_filter # - Allows the user to search the Squid access log for a specific IP # and/or keyword. # - Converts numeric timestamps in the log to human-readable dates. # - Results are saved to squid_filter.log in the current directory. # # 2) squid_audit # - Searches the Squid cache log for events where "clientAccessCheckDone" occurred. # - Converts numeric timestamps to human-readable dates. # - Requires debug_options "ALL,1 33,2 28,9" to be enabled in squid.conf. # If not enabled, the function exits with an informative error. # - Results are saved to squid_audit.log in the current directory. # # 3) squid_traffic # - Generates a traffic report from the Squid access log for a specified # analysis period (default 72 hours). # - Lists IP addresses and the number of hits to external domains. # - Flags IPs exceeding a configurable alert threshold. # - Results are saved to squid_traffic.log in the current directory. # # 4) squid_global # - Exports comprehensive Squid access log data to CSV format for a specified # analysis period (default 72 hours). # - Includes detailed fields: date, time, IP, method, HTTP code, size, cache status, # URL, domain, status classification, and error type categorization. # - Results are saved to squid_global.csv in the current directory. # # 5) squid_stats # - Generates comprehensive statistics and analytics from the Squid access log # for a specified analysis period (default 72 hours). # - Produces detailed metrics including performance data, cache hit rates, status # code analysis, bandwidth usage, top clients/domains, and error analysis. # - Generates both CSV (squid_stats.csv) and HTML (squid_stats.html) reports. # # 6) squid_ip_timeframe # - Analyzes traffic for a specific IP address within a user-defined time range # (hour range) on the current day. # - Converts UTC timestamps from the log to the system's local time zone. # - Displays detailed information including timestamp, cache code, HTTP status, # transferred bytes, method, and URL for each matching request. # - Useful for identifying activity gaps or concentrated traffic during specific # hours of the day. # - Results are saved to squid_ip_timeframe.log in the current directory. # # All logs are written to the current working directory, and the script # informs the user where to find the output files after execution. # ################################################################################ set -uo pipefail # VALIDATION -- one variable per thing validated; use directly with =~ _UH_IPV4='^(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])$' ## root check if [ "$(id -u)" != "0" ]; then echo "ERROR: This script must be run as root" exit 1 fi # prevent overlapping runs SCRIPT_LOCK="/var/lock/$(basename "$0" .sh).lock" (umask 077; : >> "$SCRIPT_LOCK") exec 200>"$SCRIPT_LOCK" if ! flock -n 200; then echo "Script $(basename "$0") is already running" exit 1 fi # DEPENDENCIES for dep in perl gawk gzip; do if ! dpkg -s "$dep" &>/dev/null; then echo "ERROR: Required dependency '$dep' is not installed." >&2 exit 1 fi done # DEPENDENCIES (squid or squid-openssl) if ! dpkg -s squid &>/dev/null && ! dpkg -s squid-openssl &>/dev/null; then echo "ERROR: 'squid' or 'squid-openssl' is not installed." >&2 exit 1 fi # LOG FILE CHECK # Modified to include all log files (current and rotated) ACCESS_LOG="/var/log/squid/access.log*" CACHE_LOG="/var/log/squid/cache.log*" # Verify at least one access log file exists if ! ls /var/log/squid/access.log* 1> /dev/null 2>&1; then echo "Access log not found: /var/log/squid/access.log*" exit 1 fi # Verify at least one cache log file exists if ! ls /var/log/squid/cache.log* 1> /dev/null 2>&1; then echo "Cache log not found: /var/log/squid/cache.log*" exit 1 fi # TIMING SCRIPT_START=$(date +%s) # FUNCTIONS squid_filter() { LOG_FILE="squid_filter.log" echo "=== Squid Filter ===" > "$LOG_FILE" read -p "Enter IP (e.g. 192.168.0.10) or leave empty: " IP read -p "Enter the word to search (e.g. google): " WORD IPNEW="" [[ "$IP" =~ $_UH_IPV4 ]] && IPNEW="$IP" if [[ "$IPNEW" ]]; then zcat -f $ACCESS_LOG 2>/dev/null | perl -pe 's/^(\d+\.\d+)/localtime($1)/e' \ | grep "$IPNEW" \ | grep -a -i -F "$WORD" >> "$LOG_FILE" else zcat -f $ACCESS_LOG 2>/dev/null | perl -pe 's/^(\d+\.\d+)/localtime($1)/e' \ | grep -a -i -F "$WORD" >> "$LOG_FILE" fi if [ $? -gt 0 ]; then echo "No records found for: $WORD" >> "$LOG_FILE" else echo "Done" >> "$LOG_FILE" fi echo "Results saved to $(pwd)/$LOG_FILE" } squid_audit() { LOG_FILE="squid_audit.log" echo "=== Squid Audit ===" > "$LOG_FILE" # Check debug_options in squid.conf SQUID_CONF="/etc/squid/squid.conf" # Adjust for your system REQUIRED_DEBUG="ALL,1 33,2 28,9" if [[ ! -f "$SQUID_CONF" ]] || ! grep -q "^debug_options\s\+$REQUIRED_DEBUG" "$SQUID_CONF"; then echo "ERROR: debug_options $REQUIRED_DEBUG is not enabled in $SQUID_CONF" | tee -a "$LOG_FILE" echo "Please enable this line and restart Squid before running this script." >> "$LOG_FILE" echo "Results saved to $(pwd)/$LOG_FILE" return fi read -p "Enter the word to search (e.g.: video): " WORD zcat -f $CACHE_LOG 2>/dev/null | perl -pe 's/^(\d+\.\d+)/localtime($1)/e' \ | grep -i "clientAccessCheckDone" \ | grep -a -i -F "$WORD" >> "$LOG_FILE" if [ $? -gt 0 ]; then echo "No records found for: $WORD" >> "$LOG_FILE" else echo "Done" >> "$LOG_FILE" fi echo "Results saved to $(pwd)/$LOG_FILE" } squid_traffic() { # Ask user for period read -p "Enter the number of hours to analyze (default 72): " USER_HOURS PERIOD_HOURS=${USER_HOURS:-72} # Variables specific to this block MIN_HITS=${MIN_HITS:-20} ALERT_THRESHOLD=${ALERT_THRESHOLD:-300} SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LOG_FILE="$SCRIPT_DIR/squid_traffic.log" # Initialize log file echo "============================================================" > "$LOG_FILE" echo "SQUID TRAFFIC ANALYSIS REPORT" >> "$LOG_FILE" echo "============================================================" >> "$LOG_FILE" echo "Analysis started: $(date '+%Y-%m-%d %H:%M:%S')" >> "$LOG_FILE" echo "Configuration:" >> "$LOG_FILE" echo "* Minimum hits : $MIN_HITS" >> "$LOG_FILE" echo "* Alert threshold: $ALERT_THRESHOLD" >> "$LOG_FILE" echo "* Analysis period: ${PERIOD_HOURS}H" >> "$LOG_FILE" echo "* Access log : /var/log/squid/access.log* (all files)" >> "$LOG_FILE" echo "------------------------------------------------------------" >> "$LOG_FILE" printf "%-8s %-15s %-60s\n" "Hits" "IP" "URL" >> "$LOG_FILE" echo "------------------------------------------------------------" >> "$LOG_FILE" # Verify access log exists if ! ls /var/log/squid/access.log* 1> /dev/null 2>&1; then echo "ERROR: Access log file not found: /var/log/squid/access.log*" | tee -a "$LOG_FILE" echo "Results saved to $LOG_FILE" return fi # Calculate cutoff timestamp NOW=$(date +%s) PERIOD=$((PERIOD_HOURS*3600)) CUTOFF=$((NOW - PERIOD)) # Generate traffic report zcat -f $ACCESS_LOG 2>/dev/null | gawk -v cutoff="$CUTOFF" '$1 > cutoff { match($7, /https?:\/\/([^\/]+)/, arr) if (arr[1] != "") print $3, arr[1] }' \ | sort \ | uniq -c \ | sort -nr \ | awk -v min="$MIN_HITS" '{if($1>=min) printf "%-8s %-15s %-60s\n", $1, $2, $3}' \ >> "$LOG_FILE" # Check for alerts ALERT_IPS=$(awk -v th="$ALERT_THRESHOLD" '$1 ~ /^[0-9]+$/ && $1+0 >= th {print $0}' "$LOG_FILE") if [[ -n "$ALERT_IPS" ]]; then ALERT_COUNT=$(echo "$ALERT_IPS" | wc -l) ALERT_MSG="ALERT: $ALERT_COUNT IP(s) exceed threshold of $ALERT_THRESHOLD hits" echo -e "$ALERT_MSG" | tee -a "$LOG_FILE" else INFO_MSG="No IPs exceed the alert threshold of $ALERT_THRESHOLD hits" echo -e "$INFO_MSG" | tee -a "$LOG_FILE" fi echo "Results saved to $LOG_FILE" } squid_global() { SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CSV_FILE="$SCRIPT_DIR/squid_global.csv" echo "WARNING: Generating this CSV may take some time depending on log size." read -p "Enter the number of hours to analyze (default 72): " PERIOD_HOURS PERIOD_HOURS=${PERIOD_HOURS:-72} if ! ls /var/log/squid/access.log* 1> /dev/null 2>&1; then echo "ERROR: Access log not found: /var/log/squid/access.log*" return fi START=$(date +%s) NOW=$(date +%s) PERIOD=$((PERIOD_HOURS * 3600)) CUTOFF=$((NOW - PERIOD)) echo "Starting CSV export..." echo "date,time,ip,method,http_code,size,cache_status,url,domain,status,error_type" > "$CSV_FILE" zcat -f $ACCESS_LOG 2>/dev/null | gawk -v cutoff="$CUTOFF" ' function extract_domain(u, d, h) { if (u == "" || u == "-") return "-" if (u ~ /^https?:\/\//) { delete d if (match(u, /https?:\/\/([^\/:]+)/, d)) return d[1] else return u } if (u ~ /^[^\/:]+:[0-9]+$/) { split(u, h, ":") return h[1] } return u } $1 > cutoff { dt = strftime("%Y-%m-%d,%H:%M:%S", $1) ip = $3 code = $4 size = $5 method = $6 url = $7 cache = $9 split(code, c, "/") status_code = c[2] if (status_code == "") status_code = "000" if (method == "-") method = "UNKNOWN" # Classify error types if (status_code == "000") { status = "ERROR" error_type = "CONNECTION_FAIL" } else if (status_code >= 400) { status = "ERROR" error_type = "HTTP_ERROR" } else { status = "OK" error_type = "-" } domain = extract_domain(url) print dt","ip","method","status_code","size","cache","url","domain","status","error_type }' >> "$CSV_FILE" echo "CSV export completed: $CSV_FILE" } squid_stats() { SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CSV_FILE="$SCRIPT_DIR/squid_stats.csv" HTML_FILE="$SCRIPT_DIR/squid_stats.html" echo "WARNING: Generating stats may take some time depending on log size." read -p "Enter the number of hours to analyze (default 72): " PERIOD_HOURS PERIOD_HOURS=${PERIOD_HOURS:-72} if ! ls /var/log/squid/access.log* 1> /dev/null 2>&1; then echo "ERROR: Access log not found: /var/log/squid/access.log*" return fi START=$(date +%s) NOW=$(date +%s) PERIOD=$((PERIOD_HOURS * 3600)) CUTOFF=$((NOW - PERIOD)) echo "Generating comprehensive statistics..." echo "Metric,Value" > "$CSV_FILE" # === BASIC METRICS === TOTAL_REQUESTS=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff' | wc -l) UNIQUE_IPS=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff {print $3}' | sort -u | wc -l) UNIQUE_DOMAINS=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff {print $7}' | sed -E 's#^https?://([^/:]+).*#\1#' | sort -u | wc -l) DATA_MB=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff {sum+=$5} END {printf "%.2f", sum/1048576}') DATA_GB=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff {sum+=$5} END {printf "%.2f", sum/1073741824}') # === STATUS CODE ANALYSIS === SUCCESS=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff && $4 ~ /\/200/' | wc -l) REDIRECTS=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff && $4 ~ /\/30[0-9]/' | wc -l) CLIENT_ERRORS=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff && $4 ~ /\/40[0-9]/' | wc -l) SERVER_ERRORS=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff && $4 ~ /\/50[0-9]/' | wc -l) CACHE_HITS=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff && $4 ~ /HIT/' | wc -l) CACHE_MISS=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff && $4 ~ /MISS/' | wc -l) # === PERCENTAGES === SUCCESS_PCT=$(awk -v s="$SUCCESS" -v t="$TOTAL_REQUESTS" 'BEGIN {if (t>0) printf "%.2f", (s/t)*100; else print 0}') CACHE_HIT_PCT=$(awk -v h="$CACHE_HITS" -v t="$TOTAL_REQUESTS" 'BEGIN {if (t>0) printf "%.2f", (h/t)*100; else print 0}') ERROR_PCT=$(awk -v e="$((CLIENT_ERRORS + SERVER_ERRORS))" -v t="$TOTAL_REQUESTS" 'BEGIN {if (t>0) printf "%.2f", (e/t)*100; else print 0}') # === PERFORMANCE METRICS === AVG_RESPONSE_SIZE=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff {sum+=$5; count++} END {if (count>0) printf "%.2f", sum/count/1024; else print 0}') REQ_PER_HOUR=$(awk -v t="$TOTAL_REQUESTS" -v h="$PERIOD_HOURS" 'BEGIN {printf "%.0f", t/h}') BANDWIDTH_MBPS=$(awk -v mb="$DATA_MB" -v h="$PERIOD_HOURS" 'BEGIN {printf "%.2f", (mb*8)/(h*3600)}') # === WRITE CSV === echo "Analysis period (hours),$PERIOD_HOURS" >> "$CSV_FILE" echo "Total requests,$TOTAL_REQUESTS" >> "$CSV_FILE" echo "Requests per hour,$REQ_PER_HOUR" >> "$CSV_FILE" echo "Unique client IPs,$UNIQUE_IPS" >> "$CSV_FILE" echo "Unique domains accessed,$UNIQUE_DOMAINS" >> "$CSV_FILE" echo "Total data transferred,${DATA_GB} GB (${DATA_MB} MB)" >> "$CSV_FILE" echo "Average bandwidth,${BANDWIDTH_MBPS} Mbps" >> "$CSV_FILE" echo "Average response size,${AVG_RESPONSE_SIZE} KB" >> "$CSV_FILE" echo "Successful requests (2xx),${SUCCESS} (${SUCCESS_PCT}%)" >> "$CSV_FILE" echo "Redirects (3xx),${REDIRECTS}" >> "$CSV_FILE" echo "Client errors (4xx),${CLIENT_ERRORS}" >> "$CSV_FILE" echo "Server errors (5xx),${SERVER_ERRORS}" >> "$CSV_FILE" echo "Total errors,$(($CLIENT_ERRORS + $SERVER_ERRORS)) (${ERROR_PCT}%)" >> "$CSV_FILE" echo "Cache hits,${CACHE_HITS} (${CACHE_HIT_PCT}%)" >> "$CSV_FILE" echo "Cache misses,${CACHE_MISS}" >> "$CSV_FILE" # === TOP LISTS === TOP_IPS=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff {count[$3]++; bytes[$3]+=$5} END { for (ip in count) printf "%s (%d req/%.1fMB)\n", ip, count[ip], bytes[ip]/1048576 }' | sort -t'(' -k2 -nr | head -5 | tr '\n' ' ') echo "Top 5 client IPs,$TOP_IPS" >> "$CSV_FILE" TOP_DOMAINS=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff { gsub(/^https?:\/\//, "", $7); gsub(/\/.*/, "", $7) count[$7]++; bytes[$7]+=$5 } END { for (domain in count) printf "%s (%d req/%.1fMB)\n", domain, count[domain], bytes[domain]/1048576 }' | sort -t'(' -k2 -nr | head -5 | tr '\n' ' ') echo "Top 5 domains by requests,$TOP_DOMAINS" >> "$CSV_FILE" TOP_ERROR_DOMAINS=$(zcat -f $ACCESS_LOG 2>/dev/null | awk -v cutoff="$CUTOFF" '$1 > cutoff && ($4 ~ /\/40[0-9]/ || $4 ~ /\/50[0-9]/) { gsub(/^https?:\/\//, "", $7); gsub(/\/.*/, "", $7) errors[$7]++ } END { for (domain in errors) printf "%s (%d errors)\n", domain, errors[domain] }' | sort -t'(' -k2 -nr | head -5 | tr '\n' ' ') echo "Top 5 error domains,$TOP_ERROR_DOMAINS" >> "$CSV_FILE" # === GENERATE HTML REPORT === { echo "" echo "" echo "" echo "" echo "" echo "Squid Proxy Statistics - Enhanced Report" echo "" echo "" echo "" echo "
" echo "

Squid Proxy Statistics

" # Main stats grid echo "
" echo "
" echo "

General Overview

" echo "
Analysis Period$PERIOD_HOURS hours
" echo "
Total Requests$(printf "%'d" $TOTAL_REQUESTS)
" echo "
Requests/Hour$REQ_PER_HOUR
" echo "
Unique IPs$UNIQUE_IPS
" echo "
Unique Domains$UNIQUE_DOMAINS
" echo "
" echo "
" echo "

Bandwidth & Performance

" echo "
Total Data${DATA_GB} GB
" echo "
Average Bandwidth${BANDWIDTH_MBPS} Mbps
" echo "
Avg Response Size${AVG_RESPONSE_SIZE} KB
" echo "
Cache Hit Rate${CACHE_HIT_PCT}%
" echo "
" echo "
" echo "

Status Analysis

" echo "
Success Rate${SUCCESS_PCT}%
" echo "
Successful (2xx)$SUCCESS
" echo "
Redirects (3xx)$REDIRECTS
" echo "
Client Errors (4xx)$CLIENT_ERRORS
" echo "
Server Errors (5xx)$SERVER_ERRORS
" echo "
" echo "
" # Detailed table echo "

Detailed Metrics

" echo "" echo "" tail -n +2 "$CSV_FILE" | while IFS=, read -r metric value; do if [[ "$metric" == *"error"* ]] || [[ "$metric" == *"Error"* ]]; then echo "" elif [[ "$metric" == *"Cache"* ]] && [[ "$value" == *"%"* ]]; then echo "" else echo "" fi done echo "
MetricValue
$metric$value
$metric$value
$metric$value
" echo "

Generated on $(date)

" echo "
" } > "$HTML_FILE" END=$(date +%s) echo "Stats CSV generated: $CSV_FILE" echo "Stats HTML generated: $HTML_FILE" echo "Summary: $TOTAL_REQUESTS requests, ${SUCCESS_PCT}% success rate, ${CACHE_HIT_PCT}% cache hit rate" } squid_ip_timeframe() { # 1. Environment Setup # Define script directory and log output path local SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" local LOG_FILE="$SCRIPT_DIR/squid_ip_timeframe.log" # Target all access logs (current, rotated, and compressed) local ACCESS_LOGS="/var/log/squid/access.log*" # Initialize log file echo "=== Squid IP Traffic by Time Range ===" > "$LOG_FILE" # 2. User Input & Validation # Prompt for IP and validate format read -p "Enter IP address (e.g. 192.168.10.42): " IP [[ ! "$IP" =~ $_UH_IPV4 ]] && { echo "Invalid IP format"; return; } # Prompt for date, default to current system date if empty read -p "Date (YYYY-MM-DD, enter for today): " USER_DATE [[ -z "$USER_DATE" ]] && USER_DATE=$(date +%Y-%m-%d) # Prompt for start and end times read -p "Start time (HH:MM): " START_TIME read -p "End time (HH:MM): " END_TIME # 3. Time Synchronization # Convert local user input (Date + Time) to Unix Epoch (Seconds since 1970) # This aligns with Squid's native timestamp format ($1) local START_EPOCH=$(date -d "$USER_DATE $START_TIME" +%s 2>/dev/null) local END_EPOCH=$(date -d "$USER_DATE $END_TIME" +%s 2>/dev/null) # Validate that the date/time conversion was successful if [[ -z "$START_EPOCH" || -z "$END_EPOCH" ]]; then echo "Error: Invalid date or time format provided." return fi # 4. Report Header Generation local TZ_LABEL=$(date +%Z) # Fetch system timezone (e.g., UTC, EST, COT) { echo "============================================================" echo "SQUID IP TIMEFRAME ANALYSIS" echo "============================================================" echo "Analysis started: $(date '+%Y-%m-%d %H:%M:%S')" echo "Configuration:" echo "* IP Address : $IP" echo "* Time range : $START_TIME to $END_TIME ($TZ_LABEL)" echo "* Date Target : $USER_DATE" echo "* Access log : $ACCESS_LOGS" echo "------------------------------------------------------------" printf "%-12s %-15s %-8s %-12s %-8s %-60s\n" "Time(Local)" "Status/Result" "HTTP" "Bytes" "Method" "URL" echo "------------------------------------------------------------" } >> "$LOG_FILE" # 5. Optimized Log Processing local FOUND=0 # zcat -f handles both compressed (.gz) and plain text logs seamlessly # awk filters by IP and Epoch range before the data reaches the Bash loop while read -r ts status_code bytes method url; do # Convert Epoch timestamp back to human-readable local time # ${ts%.*} removes any millisecond decimals to prevent date command errors local L_TIME=$(date -d "@${ts%.*}" "+%H:%M:%S" 2>/dev/null) # Convert Bytes to human-readable units (MB/KB/B) using Bash arithmetic local BYTES_FMT if [ "$bytes" -ge 1048576 ]; then BYTES_FMT="$((bytes / 1048576)) MB" elif [ "$bytes" -ge 1024 ]; then BYTES_FMT="$((bytes / 1024)) KB" else BYTES_FMT="${bytes} B" fi # Extract Squid Cache status and HTTP result code from field 4 (e.g., TCP_MISS/200) local CACHE_S=$(echo "$status_code" | cut -d'/' -f1) local HTTP_S=$(echo "$status_code" | cut -d'/' -f2) # Append formatted entry to the result file printf "%-12s %-15s %-8s %-12s %-8s %-60s\n" \ "$L_TIME" "$CACHE_S" "$HTTP_S" "$BYTES_FMT" "$method" "$url" >> "$LOG_FILE" ((FOUND++)) done < <(zcat -f $ACCESS_LOGS 2>/dev/null | awk -v ip="$IP" -v s="$START_EPOCH" -v e="$END_EPOCH" \ '$1 >= s && $1 <= e && $3 == ip {print $1, $4, $5, $6, $7}') # 6. Report Footer { echo "------------------------------------------------------------" if [ $FOUND -gt 0 ]; then echo "Total entries found: $FOUND" else echo "No entries found for $IP in that timeframe." fi echo "============================================================" } >> "$LOG_FILE" echo "Done! Results saved in: $LOG_FILE" } # MAIN MENU echo "================ SQUID ANALYSIS TOOL ================" echo "Select an option:" echo "1) Squid Filter" echo "2) Squid Audit" echo "3) Squid Traffic (Report with alerts)" echo "4) Squid Global CSV export" echo "5) Squid Stats CSV export" echo "6) IP Timeframe Analysis (traffic by hour range today)" read -p "Enter choice [1-6]: " CHOICE case "$CHOICE" in 1) squid_filter ;; 2) squid_audit ;; 3) squid_traffic ;; 4) squid_global ;; 5) squid_stats ;; 6) squid_ip_timeframe ;; *) echo "Invalid option" ;; esac SCRIPT_END=$(date +%s) echo "Total script duration: $((SCRIPT_END - SCRIPT_START)) seconds"