#!/usr/bin/env bash
#
# onx-firewall-recent-blocks — Son engellenen bağlantıları journald + nftables sayaçlarından çek.
#
# Data sources:
#   1. journald (systemd journal) — kernel.log_prefix ile etiketlenmiş onox-* drop satırları
#   2. fail2ban.sqlite3 — son ban olayları (jail bazlı)
#   3. nftables counter — chain başına toplam drop sayısı
#
# Input (stdin JSON): {"limit": 100, "since_minutes": 60}
# Output: {"events":[{...}],"counters":{...}}

set -euo pipefail

input="$(cat 2>/dev/null || echo '{}')"
limit="$(echo "$input" | jq -r '.limit // 100')"
since_min="$(echo "$input" | jq -r '.since_minutes // 60')"

# Validate
[[ "$limit"     =~ ^[0-9]+$ ]] && (( limit < 1000 )) || limit=100
[[ "$since_min" =~ ^[0-9]+$ ]] || since_min=60

readonly LOG_TAG="onox-recent-blocks"
events_file="$(mktemp)"
trap 'rm -f "$events_file"' EXIT

# ── Source 1: journald — onox prefix'li drop log'ları ─────────────────────
# nftables `log prefix "onox-block "` ile etiketlenmiş kernel mesajlarını ara.
# Format örneği: kernel: onox-block IN=eth0 SRC=1.2.3.4 PROTO=TCP DPT=22
if command -v journalctl &>/dev/null; then
    journalctl --since "${since_min} minutes ago" --no-pager 2>/dev/null \
        | grep -E "onox-[a-z-]+ " \
        | tail -n "$limit" \
        | while IFS= read -r line; do
        # Parse fields
        ts=$(echo "$line" | awk '{print $1, $2, $3}')
        src=$(echo "$line" | grep -oE 'SRC=[0-9a-fA-F.:]+' | head -1 | cut -d= -f2)
        proto=$(echo "$line" | grep -oE 'PROTO=[A-Z]+' | head -1 | cut -d= -f2)
        dpt=$(echo "$line" | grep -oE 'DPT=[0-9]+' | head -1 | cut -d= -f2)
        rule=$(echo "$line" | grep -oE 'onox-[a-z-]+' | head -1)

        [[ -z "$src" ]] && continue

        # Service detect from port
        service="other"
        case "$dpt" in
            22)            service="ssh" ;;
            25|465|587)    service="smtp" ;;
            80)            service="http" ;;
            443)           service="https" ;;
            110|995)       service="pop3" ;;
            143|993)       service="imap" ;;
            21|20)         service="ftp" ;;
            53)            service="dns" ;;
            3306)          service="mysql" ;;
            *)             service="port-${dpt:-?}" ;;
        esac

        # Country code via local GeoIP cache (varsa)
        cc=""
        if [[ -d /var/lib/onox/geoip/cidrs ]] && command -v grepcidr &>/dev/null; then
            for f in /var/lib/onox/geoip/cidrs/*.txt; do
                [[ -f "$f" ]] || continue
                if grepcidr "$src" "$f" &>/dev/null; then
                    cc="$(basename "$f" .txt | tr '[:lower:]' '[:upper:]')"
                    break
                fi
            done
        fi

        jq -nc \
            --arg ts "$ts" \
            --arg src "$src" \
            --arg cc "$cc" \
            --arg service "$service" \
            --arg rule "$rule" \
            --arg proto "${proto:-?}" \
            '{source_ip:$src,country_code:$cc,service:$service,rule_type:$rule,action:"blocked",hits:1,timestamp:$ts,protocol:$proto}' \
            >> "$events_file"
    done
fi

# ── Source 2: fail2ban SQLite — son N ban olayları ────────────────────────
if [[ -r /var/lib/fail2ban/fail2ban.sqlite3 ]] && command -v sqlite3 &>/dev/null; then
    # bans tablosu: jail, ip, timeofban, data, bantime
    sqlite3 -separator "|" /var/lib/fail2ban/fail2ban.sqlite3 \
        "SELECT jail, ip, datetime(timeofban,'unixepoch') as ts
         FROM bans
         WHERE timeofban >= strftime('%s','now') - ${since_min}*60
         ORDER BY timeofban DESC
         LIMIT $limit" 2>/dev/null \
    | while IFS='|' read -r jail ip ts; do
        [[ -z "$ip" ]] && continue

        cc=""
        if [[ -d /var/lib/onox/geoip/cidrs ]] && command -v grepcidr &>/dev/null; then
            for f in /var/lib/onox/geoip/cidrs/*.txt; do
                [[ -f "$f" ]] || continue
                if grepcidr "$ip" "$f" &>/dev/null; then
                    cc="$(basename "$f" .txt | tr '[:lower:]' '[:upper:]')"
                    break
                fi
            done
        fi

        jq -nc \
            --arg ip "$ip" --arg cc "$cc" --arg jail "$jail" --arg ts "$ts" \
            '{source_ip:$ip,country_code:$cc,service:$jail,rule_type:"fail2ban-\($jail)",action:"banned",hits:1,timestamp:$ts}' \
            >> "$events_file"
    done
fi

# ── nftables counter snapshot (chain başı toplam) ─────────────────────────
counters_json="{}"
if command -v nft &>/dev/null && nft list table inet onox &>/dev/null; then
    counters_json="$(nft -j list table inet onox 2>/dev/null \
        | jq '[.nftables[]?.rule? | select(.expr[]?.counter?) | {
                comment: .comment,
                packets: (.expr[] | select(.counter?) | .counter.packets),
                bytes:   (.expr[] | select(.counter?) | .counter.bytes)
            }] | map(select(.comment != null))' 2>/dev/null || echo '[]')"
fi

# ── Aggregate events ──────────────────────────────────────────────────────
# Bir IP+service kombinasyonunu deduplicate et, hits topla
events_json="[]"
if [[ -s "$events_file" ]]; then
    events_json="$(jq -s \
        'group_by(.source_ip + "/" + .service)
         | map(.[0] + {hits: (map(.hits) | add)})
         | sort_by(.timestamp) | reverse
         | .[0:'"$limit"']' \
        "$events_file" 2>/dev/null || echo '[]')"
fi

jq -nc \
    --argjson events "$events_json" \
    --argjson counters "$counters_json" \
    --argjson limit "$limit" \
    --argjson since_min "$since_min" \
    '{ok:true,events:$events,counters:$counters,limit:$limit,since_minutes:$since_min}'
