#!/bin/bash
# diag-windscribe-connect.sh — Diagnostic script for testing ctrld dns-intercept
# during Windscribe VPN connection on macOS.
#
# Usage: sudo ./diag-windscribe-connect.sh
#
# Run this BEFORE connecting Windscribe. It polls every 0.5s and captures:
#   1. pf anchor state (are ctrld anchors present?)
#   2. pf state table entries (rdr interception working?)
#   3. ctrld log events (watchdog, rebootstrap, errors)
#   4. scutil DNS resolver state
#   5. Active tunnel interfaces
#   6. dig test query results
#
# Output goes to /tmp/diag-windscribe-<timestamp>/
# Press Ctrl-C to stop. A summary is printed at the end.

set -e

if [ "$(id -u)" -ne 0 ]; then
    echo "ERROR: Must run as root (sudo)"
    exit 1
fi

CTRLD_LOG="${CTRLD_LOG:-/tmp/dns.log}"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
OUTDIR="/tmp/diag-windscribe-${TIMESTAMP}"
mkdir -p "$OUTDIR"

echo "=== Windscribe + ctrld DNS Intercept Diagnostic ==="
echo "Output: $OUTDIR"
echo "ctrld log: $CTRLD_LOG"
echo ""
echo "1. Start this script"
echo "2. Connect Windscribe"
echo "3. Wait ~30 seconds"
echo "4. Try: dig popads.net / dig @127.0.0.1 popads.net"
echo "5. Ctrl-C to stop and see summary"
echo ""
echo "Polling every 0.5s... Press Ctrl-C to stop."
echo ""

# Track ctrld log position
if [ -f "$CTRLD_LOG" ]; then
    LOG_START_LINE=$(wc -l < "$CTRLD_LOG")
else
    LOG_START_LINE=0
fi

ITER=0
DIG_FAIL=0
DIG_OK=0
ANCHOR_MISSING=0
ANCHOR_PRESENT=0
PF_WIPE_COUNT=0
FORCE_REBOOT_COUNT=0
LAST_TUNNEL_IFACES=""

cleanup() {
    echo ""
    echo "=== Stopping diagnostic ==="

    # Capture final state
    echo "--- Final pf state ---" > "$OUTDIR/final-pfctl.txt"
    pfctl -sa 2>/dev/null >> "$OUTDIR/final-pfctl.txt" 2>&1 || true

    echo "--- Final scutil ---" > "$OUTDIR/final-scutil.txt"
    scutil --dns >> "$OUTDIR/final-scutil.txt" 2>&1 || true

    # Extract ctrld log events since start
    if [ -f "$CTRLD_LOG" ]; then
        tail -n +$((LOG_START_LINE + 1)) "$CTRLD_LOG" > "$OUTDIR/ctrld-events.log" 2>/dev/null || true

        # Extract key events
        echo "--- Watchdog events ---" > "$OUTDIR/summary-watchdog.txt"
        grep -i "watchdog\|anchor.*missing\|anchor.*restored\|force-reset\|re-bootstrapping\|force re-bootstrapping" "$OUTDIR/ctrld-events.log" >> "$OUTDIR/summary-watchdog.txt" 2>/dev/null || true

        echo "--- Errors ---" > "$OUTDIR/summary-errors.txt"
        grep '"level":"error"' "$OUTDIR/ctrld-events.log" >> "$OUTDIR/summary-errors.txt" 2>/dev/null || true

        echo "--- Network changes ---" > "$OUTDIR/summary-network.txt"
        grep -i "Network change\|tunnel interface\|Ignoring interface" "$OUTDIR/ctrld-events.log" >> "$OUTDIR/summary-network.txt" 2>/dev/null || true

        echo "--- Transport resets ---" > "$OUTDIR/summary-transport.txt"
        grep -i "re-bootstrap\|force.*bootstrap\|dialing to\|connected to" "$OUTDIR/ctrld-events.log" >> "$OUTDIR/summary-transport.txt" 2>/dev/null || true

        # Count key events
        PF_WIPE_COUNT=$(grep -c "anchor.*missing\|restoring pf" "$OUTDIR/ctrld-events.log" 2>/dev/null || echo 0)
        FORCE_REBOOT_COUNT=$(grep -c "force re-bootstrapping\|force-reset" "$OUTDIR/ctrld-events.log" 2>/dev/null || echo 0)
        DEADLINE_COUNT=$(grep -c "context deadline exceeded" "$OUTDIR/ctrld-events.log" 2>/dev/null || echo 0)
        FALLBACK_COUNT=$(grep -c "OS resolver retry query successful" "$OUTDIR/ctrld-events.log" 2>/dev/null || echo 0)
    fi

    echo ""
    echo "========================================="
    echo "         DIAGNOSTIC SUMMARY"
    echo "========================================="
    echo "Duration: $ITER iterations (~$((ITER / 2))s)"
    echo ""
    echo "pf Anchor Status:"
    echo "  Present: $ANCHOR_PRESENT times"
    echo "  Missing: $ANCHOR_MISSING times"
    echo ""
    echo "dig Tests (popads.net):"
    echo "  Success: $DIG_OK"
    echo "  Failed:  $DIG_FAIL"
    echo ""
    echo "ctrld Log Events:"
    echo "  pf wipes detected:      $PF_WIPE_COUNT"
    echo "  Force rebootstraps:     $FORCE_REBOOT_COUNT"
    echo "  Context deadline errors: ${DEADLINE_COUNT:-0}"
    echo "  OS resolver fallbacks:   ${FALLBACK_COUNT:-0}"
    echo ""
    echo "Last tunnel interfaces: ${LAST_TUNNEL_IFACES:-none}"
    echo ""
    echo "Files saved to: $OUTDIR/"
    echo "  final-pfctl.txt        — full pfctl -sa at exit"
    echo "  final-scutil.txt       — scutil --dns at exit"
    echo "  ctrld-events.log       — ctrld log during test"
    echo "  summary-watchdog.txt   — watchdog events"
    echo "  summary-errors.txt     — errors"
    echo "  summary-transport.txt  — transport reset events"
    echo "  timeline.log           — per-iteration state"
    echo "========================================="
    exit 0
}

trap cleanup INT TERM

while true; do
    ITER=$((ITER + 1))
    NOW=$(date '+%H:%M:%S.%3N' 2>/dev/null || date '+%H:%M:%S')

    # 1. Check pf anchor presence
    ANCHOR_STATUS="MISSING"
    if pfctl -sr 2>/dev/null | grep -q "com.controld.ctrld"; then
        ANCHOR_STATUS="PRESENT"
        ANCHOR_PRESENT=$((ANCHOR_PRESENT + 1))
    else
        ANCHOR_MISSING=$((ANCHOR_MISSING + 1))
    fi

    # 2. Check tunnel interfaces
    TUNNEL_IFACES=$(ifconfig -l 2>/dev/null | tr ' ' '\n' | grep -E '^(utun|ipsec|ppp|tap|tun)' | \
        while read iface; do
            # Only list interfaces that are UP and have an IP
            if ifconfig "$iface" 2>/dev/null | grep -q "inet "; then
                echo -n "$iface "
            fi
        done)
    TUNNEL_IFACES=$(echo "$TUNNEL_IFACES" | xargs)  # trim
    if [ -n "$TUNNEL_IFACES" ]; then
        LAST_TUNNEL_IFACES="$TUNNEL_IFACES"
    fi

    # 3. Count rdr states (three-part = intercepted)
    RDR_COUNT=$(pfctl -ss 2>/dev/null | grep -c "127.0.0.1:53 <-" || echo 0)

    # 4. Quick dig test (0.5s timeout)
    DIG_RESULT="SKIP"
    if [ $((ITER % 4)) -eq 0 ]; then  # every 2 seconds
        if dig +time=1 +tries=1 popads.net A @127.0.0.1 +short >/dev/null 2>&1; then
            DIG_RESULT="OK"
            DIG_OK=$((DIG_OK + 1))
        else
            DIG_RESULT="FAIL"
            DIG_FAIL=$((DIG_FAIL + 1))
        fi
    fi

    # 5. Check latest ctrld log for recent errors
    RECENT_ERR=""
    if [ -f "$CTRLD_LOG" ]; then
        RECENT_ERR=$(tail -5 "$CTRLD_LOG" 2>/dev/null | grep -o '"message":"[^"]*deadline[^"]*"' | tail -1 || true)
    fi

    # Output timeline
    LINE="[$NOW] anchor=$ANCHOR_STATUS rdr_states=$RDR_COUNT tunnels=[$TUNNEL_IFACES] dig=$DIG_RESULT $RECENT_ERR"
    echo "$LINE"
    echo "$LINE" >> "$OUTDIR/timeline.log"

    sleep 0.5
done
