#!/usr/bin/env bash
set -euo pipefail

usage() {
  cat <<USAGE
Usage: $(basename "$0") <capture.pcap> [output_dir]

Lightweight PCAP triage for CTF / DFIR:
- capinfos summary
- tshark stats / conversations / endpoints
- protocol-specific extracts
- Zeek (if installed)
- Suricata EVE JSON (if installed)
- tcpflow (if installed)
- HTTP object export
- quick string / IOC hunts
USAGE
}

have() { command -v "$1" >/dev/null 2>&1; }

[[ $# -lt 1 ]] && usage && exit 1
PCAP="$1"
OUTDIR="${2:-pcap_triage_$(date +%Y%m%d_%H%M%S)}"

[[ -f "$PCAP" ]] || { echo "[-] File not found: $PCAP" >&2; exit 1; }
mkdir -p "$OUTDIR"/{raw,stats,extracts,zeek,suricata,tcpflow,notes}

log() { printf '[+] %s\n' "$*"; }
run_or_note() {
  local name="$1"; shift
  if "$@"; then
    return 0
  else
    printf '[!] failed: %s\n' "$name" >> "$OUTDIR/notes/errors.txt"
    return 1
  fi
}

log "Saving capinfos"
if have capinfos; then
  capinfos "$PCAP" > "$OUTDIR/stats/capinfos.txt"
fi

if have tshark; then
  log "Running tshark overview"
  tshark -r "$PCAP" -q -z io,phs > "$OUTDIR/stats/protocol_hierarchy.txt"
  tshark -r "$PCAP" -q -z conv,ip > "$OUTDIR/stats/conversations_ip.txt"
  tshark -r "$PCAP" -q -z conv,tcp > "$OUTDIR/stats/conversations_tcp.txt"
  tshark -r "$PCAP" -q -z conv,udp > "$OUTDIR/stats/conversations_udp.txt"
  tshark -r "$PCAP" -q -z endpoints,ip > "$OUTDIR/stats/endpoints_ip.txt"

  log "Extracting common fields"
  tshark -r "$PCAP" -Y http.request -T fields -e tcp.stream -e ip.src -e http.host -e http.request.method -e http.request.uri \
    > "$OUTDIR/raw/http_requests.tsv" || true
  tshark -r "$PCAP" -Y dns -T fields -e frame.time_epoch -e ip.src -e dns.qry.name -e dns.a \
    > "$OUTDIR/raw/dns.tsv" || true
  tshark -r "$PCAP" -Y tls.handshake.extensions_server_name -T fields -e ip.src -e tls.handshake.extensions_server_name \
    > "$OUTDIR/raw/tls_sni.tsv" || true
  tshark -r "$PCAP" -Y smb2.filename -T fields -e ip.src -e smb2.filename \
    > "$OUTDIR/raw/smb_files.tsv" || true
  tshark -r "$PCAP" -Y ftp.request.arg -T fields -e ip.src -e ftp.request.command -e ftp.request.arg \
    > "$OUTDIR/raw/ftp.tsv" || true
  tshark -r "$PCAP" -Y icmp -T fields -e frame.time_epoch -e ip.src -e ip.dst -e data \
    > "$OUTDIR/raw/icmp.tsv" || true

  log "Keyword hunts"
  tshark -r "$PCAP" -Y 'frame contains "flag"' > "$OUTDIR/raw/hits_flag.txt" || true
  tshark -r "$PCAP" -Y 'frame contains "password"' > "$OUTDIR/raw/hits_password.txt" || true
  tshark -r "$PCAP" -Y 'frame contains "token"' > "$OUTDIR/raw/hits_token.txt" || true
  tshark -r "$PCAP" -Y 'frame contains "cookie"' > "$OUTDIR/raw/hits_cookie.txt" || true

  log "Exporting HTTP objects"
  mkdir -p "$OUTDIR/extracts/http_objects"
  tshark -r "$PCAP" --export-objects http,"$OUTDIR/extracts/http_objects" >/dev/null 2>&1 || true

  log "Dumping raw packet data"
  tshark -r "$PCAP" -T fields -e data > "$OUTDIR/raw/payload_hex.txt" || true
fi

log "Low-tech strings hunt"
strings -n 6 "$PCAP" | tee "$OUTDIR/raw/strings.txt" >/dev/null
rg -ni 'flag|pass|password|token|cookie|csrf|bearer|authorization|secret|admin|login' "$OUTDIR/raw/strings.txt" \
  > "$OUTDIR/raw/strings_hits.txt" 2>/dev/null || true

if have zeek; then
  log "Running Zeek"
  (cd "$OUTDIR/zeek" && zeek -r "$(realpath "$PCAP")") || true
fi

if have suricata; then
  log "Running Suricata"
  suricata -r "$PCAP" -l "$OUTDIR/suricata" >/dev/null 2>&1 || true
fi

if have tcpflow; then
  log "Running tcpflow"
  tcpflow -r "$PCAP" -o "$OUTDIR/tcpflow" >/dev/null 2>&1 || true
fi

if have python3; then
  log "Building a quick summary"
  python3 - "$OUTDIR" <<'PY'
from pathlib import Path
import re
import sys
out = Path(sys.argv[1])
summary = []
for name in [
    'stats/capinfos.txt','stats/protocol_hierarchy.txt','stats/conversations_ip.txt',
    'raw/http_requests.tsv','raw/dns.tsv','raw/tls_sni.tsv','raw/strings_hits.txt'
]:
    p = out / name
    if p.exists() and p.stat().st_size:
        summary.append(f'== {name} ==')
        try:
            summary.extend(p.read_text(errors='ignore').splitlines()[:20])
        except Exception:
            pass
        summary.append('')
(out / 'notes/summary.txt').write_text('\n'.join(summary))
PY
fi

cat > "$OUTDIR/notes/next_steps.txt" <<'STEPS'
Suggested next steps:
1. Read stats/protocol_hierarchy.txt and stats/conversations_*.txt
2. Review raw/http_requests.tsv, raw/dns.tsv, raw/tls_sni.tsv
3. Search raw/strings_hits.txt and the tcpflow directory
4. Inspect extracts/http_objects/
5. If Zeek ran: review zeek/http.log, zeek/dns.log, zeek/files.log
6. If Suricata ran: inspect suricata/eve.json with jq
STEPS

log "Done. Output: $OUTDIR"
