#!/bin/bash
#
# HTTP Attack Analyzer
# Analyzes Apache/Nginx log entries for attack patterns using signature database
#
# Requires: attack-signatures.sh

# Source attack signatures
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/attack-signatures.sh" 2>/dev/null || {
    echo "ERROR: attack-signatures.sh not found" >&2
    return 1
}

# Analyze a single HTTP request log line
# Input: Apache/Nginx combined log format
# Returns: threat_score||attack_types||matched_signatures||ip||uri
# Example: "85||SQLI,XSS||union_select,script_tag||192.168.1.100||/index.php?id=1"
analyze_http_log_line() {
    local log_line="$1"

    # Parse log line (Apache/Nginx combined format)
    # 192.168.1.1 - - [12/Dec/2025:10:30:45 +0000] "GET /index.php?id=1 HTTP/1.1" 200 1234 "-" "Mozilla/5.0"

    # Extract components using regex
    if [[ "$log_line" =~ ^([0-9.]+)[[:space:]].*\"([A-Z]+)[[:space:]]([^[:space:]]+)[[:space:]]HTTP/[0-9.]+\"[[:space:]]([0-9]+)[[:space:]]([0-9-]+)[[:space:]]\"([^\"]*)\"[[:space:]]\"([^\"]*)\" ]]; then
        local ip="${BASH_REMATCH[1]}"
        local method="${BASH_REMATCH[2]}"
        local uri="${BASH_REMATCH[3]}"
        local status="${BASH_REMATCH[4]}"
        local size="${BASH_REMATCH[5]}"
        local referer="${BASH_REMATCH[6]}"
        local user_agent="${BASH_REMATCH[7]}"
    else
        # Failed to parse
        echo "0||PARSE_ERROR||||||"
        return 1
    fi

    # Build complete request string for analysis
    local full_request="$method $uri HTTP/1.1
Referer: $referer
User-Agent: $user_agent"

    # Detect attacks using signature database
    local attack_result=$(detect_all_attack_signatures "$full_request" 2>/dev/null)

    if [ -n "$attack_result" ]; then
        # Parse result: max_severity||match_count||matches...
        local max_severity="${attack_result%%||*}"
        local temp="${attack_result#*||}"
        local match_count="${temp%%||*}"
        local matches="${temp#*||}"

        # Extract attack types and signatures
        local attack_types=()
        local signatures=()

        # Parse each match (format: severity||category||pattern||description)
        IFS=' ' read -ra match_array <<< "$matches"
        for match in "${match_array[@]}"; do
            # Extract category and pattern name
            local match_sev="${match%%||*}"
            local match_temp="${match#*||}"
            local category="${match_temp%%||*}"
            match_temp="${match_temp#*||}"
            local pattern="${match_temp%%||*}"

            attack_types+=("$category")
            signatures+=("$pattern")
        done

        # Remove duplicates
        local unique_types=$(printf '%s\n' "${attack_types[@]}" | sort -u | tr '\n' ',' | sed 's/,$//')
        local unique_sigs=$(printf '%s\n' "${signatures[@]}" | sort -u | tr '\n' ',' | sed 's/,$//')

        # Calculate final threat score
        local threat_score=$max_severity

        # Boost score for multiple attack types
        if [ "$match_count" -gt 1 ]; then
            threat_score=$((threat_score + (match_count - 1) * 5))
        fi

        # Boost for suspicious status codes
        case "$status" in
            200) threat_score=$((threat_score + 10)) ;;  # Success = higher threat
            500|502|503) threat_score=$((threat_score + 5)) ;;   # Error might indicate exploit attempt
        esac

        # Cap at 100
        [ "$threat_score" -gt 100 ] && threat_score=100

        # Return: threat_score||attack_types||signatures||ip||uri
        echo "$threat_score||${unique_types}||${unique_sigs}||$ip||$uri"
        return 0
    else
        # No pattern matches - check for suspicious indicators
        local suspicious_score=0
        local indicators=()

        # Unusual HTTP methods
        case "$method" in
            PUT|DELETE|TRACE|CONNECT|OPTIONS)
                suspicious_score=$((suspicious_score + 30))
                indicators+=("unusual_method:$method")
                ;;
        esac

        # Very long URIs (>500 chars)
        if [ "${#uri}" -gt 500 ]; then
            suspicious_score=$((suspicious_score + 20))
            indicators+=("long_uri:${#uri}")
        fi

        # Multiple encoding layers
        if echo "$uri" | grep -q '%25'; then
            suspicious_score=$((suspicious_score + 25))
            indicators+=("double_encoding")
        fi

        # Suspicious user agents
        if echo "$user_agent" | grep -iEq "(nikto|sqlmap|nmap|masscan|burp|metasploit|acunetix|nessus|w3af)"; then
            suspicious_score=$((suspicious_score + 40))
            indicators+=("scanner_ua")
        fi

        # Empty or suspicious referer
        if [ "$referer" = "-" ] && [ "$method" = "POST" ]; then
            suspicious_score=$((suspicious_score + 15))
            indicators+=("no_referer_post")
        fi

        # Excessive parameters (possible fuzzing)
        local param_count=$(echo "$uri" | grep -o '&' | wc -l)
        if [ "$param_count" -gt 20 ]; then
            suspicious_score=$((suspicious_score + 20))
            indicators+=("excessive_params:$param_count")
        fi

        if [ "$suspicious_score" -gt 0 ]; then
            local indicator_str=$(IFS=,; echo "${indicators[*]}")
            echo "$suspicious_score||SUSPICIOUS||${indicator_str}||$ip||$uri"
            return 0
        fi
    fi

    # Clean request
    echo "0||CLEAN||||$ip||$uri"
    return 0
}

# Batch analyze multiple log lines
# Input: File path or stdin
# Output: Summary statistics + threat list
analyze_http_log_batch() {
    local log_file="$1"
    local time_window="${2:-300}"  # Default 5 minutes (unused for now)

    local total_requests=0
    local clean_requests=0
    local suspicious_requests=0
    local attack_requests=0
    local critical_attacks=0

    declare -A ip_threats
    declare -A attack_type_counts

    # Process log lines
    while IFS= read -r line; do
        [ -z "$line" ] && continue

        total_requests=$((total_requests + 1))

        local result=$(analyze_http_log_line "$line")
        local threat_score="${result%%||*}"
        local temp="${result#*||}"
        local attack_types="${temp%%||*}"

        # Categorize
        if [ "$threat_score" -eq 0 ]; then
            clean_requests=$((clean_requests + 1))
        elif [ "$threat_score" -lt 50 ]; then
            suspicious_requests=$((suspicious_requests + 1))
        else
            attack_requests=$((attack_requests + 1))

            # Count as critical if score >= 85
            [ "$threat_score" -ge 85 ] && critical_attacks=$((critical_attacks + 1))

            # Track by IP (extract IP from result)
            local ip_temp="${result##*||}"
            ip_temp="${ip_temp#*||}"
            local ip="${ip_temp%%||*}"

            ip_threats["$ip"]=$((${ip_threats[$ip]:-0} + threat_score))

            # Track attack types
            IFS=',' read -ra types <<< "$attack_types"
            for type in "${types[@]}"; do
                [ -n "$type" ] && attack_type_counts["$type"]=$((${attack_type_counts[$type]:-0} + 1))
            done
        fi
    done < <(if [ -n "$log_file" ] && [ -f "$log_file" ]; then cat "$log_file"; else cat; fi)

    # Generate summary
    echo "SUMMARY||$total_requests||$clean_requests||$suspicious_requests||$attack_requests||$critical_attacks"

    # Top threatening IPs
    local top_ips=""
    for ip in "${!ip_threats[@]}"; do
        top_ips+="$ip:${ip_threats[$ip]} "
    done
    echo "TOP_IPS||$(echo "$top_ips" | tr ' ' '\n' | sort -t: -k2 -nr | head -10 | tr '\n' ' ' | sed 's/ $//')"

    # Attack type distribution
    local attack_dist=""
    for type in "${!attack_type_counts[@]}"; do
        attack_dist+="$type:${attack_type_counts[$type]} "
    done
    echo "ATTACK_TYPES||$(echo "$attack_dist" | tr ' ' '\n' | sort -t: -k2 -nr | tr '\n' ' ' | sed 's/ $//')"
}

# Real-time monitoring mode
# Watches log file and reports attacks as they happen
# Usage: monitor_http_log_realtime "/var/log/apache2/access_log" "callback_function_name"
monitor_http_log_realtime() {
    local log_file="$1"
    local callback_function="$2"  # Function to call with results

    if [ ! -f "$log_file" ]; then
        echo "ERROR: Log file not found: $log_file" >&2
        return 1
    fi

    tail -f "$log_file" 2>/dev/null | while IFS= read -r line; do
        [ -z "$line" ] && continue

        local result=$(analyze_http_log_line "$line")
        local threat_score="${result%%||*}"

        # Only report threats (score > 0)
        if [ "$threat_score" -gt 0 ]; then
            # Call callback function with result
            if type "$callback_function" &>/dev/null; then
                "$callback_function" "$result" "$line"
            else
                # Default: print to stdout
                echo "[THREAT:$threat_score] $result"
            fi
        fi
    done
}

# Parse analysis result into components
# Usage: parse_http_analysis_result "$result"
# Sets global variables: THREAT_SCORE, ATTACK_TYPES, SIGNATURES, IP_ADDR, URI
parse_http_analysis_result() {
    local result="$1"

    THREAT_SCORE="${result%%||*}"
    local temp="${result#*||}"
    ATTACK_TYPES="${temp%%||*}"
    temp="${temp#*||}"
    SIGNATURES="${temp%%||*}"
    temp="${temp#*||}"
    IP_ADDR="${temp%%||*}"
    URI="${temp#*||}"
}

# Format threat for display
# Usage: format_threat_display "$result"
format_threat_display() {
    local result="$1"

    parse_http_analysis_result "$result"

    local severity_label="LOW"
    local color="\033[0;36m"  # Cyan

    if [ "$THREAT_SCORE" -ge 85 ]; then
        severity_label="CRITICAL"
        color="\033[0;31m"  # Red
    elif [ "$THREAT_SCORE" -ge 70 ]; then
        severity_label="HIGH"
        color="\033[1;31m"  # Bright red
    elif [ "$THREAT_SCORE" -ge 50 ]; then
        severity_label="MEDIUM"
        color="\033[1;33m"  # Yellow
    fi

    echo -e "${color}[$severity_label:$THREAT_SCORE]${NC} $IP_ADDR → $ATTACK_TYPES"
    echo "  URI: ${URI:0:100}"
    [ -n "$SIGNATURES" ] && echo "  Signatures: $SIGNATURES"
}

# Export functions for use in subshells
export -f analyze_http_log_line
export -f analyze_http_log_batch
export -f monitor_http_log_realtime
export -f parse_http_analysis_result
export -f format_threat_display
