#!/bin/bash
# netdiag.sh — diagnostica (y prueba un fix) el camino DHCP del lab de red, todo como root en una corrida.
# Corré:  sudo bash scripts/netdiag.sh
# Deja un reporte legible en work/netdiag.txt (chmod 644) y lo imprime.
set -u
cd "$(dirname "$0")/.." || exit 1
BR="${BR:-hmtap0}"; TAP="${TAP:-hmtap0}"; SUBNET="${SUBNET:-192.168.100}"; VMMAC="52:54:00:12:34:56"
OUT=work/netdiag.txt
DNSLOG=/tmp/hmdnsmasq.log
mkdir -p work
exec > >(tee "$OUT") 2>&1

[ "$(id -u)" = 0 ] || { echo "corré con: sudo bash scripts/netdiag.sh"; exit 1; }
echo "===== netdiag ====="

run_test() { KVM=1 MEM=4096 DEADLINE=45 LOG=work/netdiag-run.log python3 scripts/drive-netup.py >/dev/null 2>&1; }

echo; echo "### 1. firewall del host (nft) ###"
echo "-- base chains input + policies --"
nft list ruleset 2>/dev/null | grep -iE 'table |chain |hook (input|forward|prerouting)|policy|type ' | head -40
INPUT_DROP=$(nft list ruleset 2>/dev/null | grep -iE 'hook input' | grep -ci 'policy drop')
echo "input-hook chains con policy drop: $INPUT_DROP"

echo; echo "### 2. captura DHCP en $TAP (egress del VM) + $BR mientras manda DISCOVER ###"
command -v tcpdump >/dev/null || echo "(tcpdump ausente — salteo captura)"
: > /tmp/netdiag.pcap.txt; : > /tmp/netdiag.br.txt
echo "estado del tap/bridge ANTES (idle):"; ip -br link show "$TAP"; ip -br link show "$BR"
if command -v tcpdump >/dev/null; then
    timeout 55 tcpdump -i "$TAP" -nnev 'udp port 67 or udp port 68' > /tmp/netdiag.pcap.txt 2>/dev/null &
    TPID=$!
    timeout 55 tcpdump -i "$BR"  -nnev 'udp port 67 or udp port 68' > /tmp/netdiag.br.txt   2>/dev/null &
    TPID2=$!; sleep 1
fi
run_test
sleep 1; for pid in ${TPID:-} ${TPID2:-}; do kill "$pid" 2>/dev/null; wait "$pid" 2>/dev/null; done
echo "-- DISCOVER/Offer en el TAP $TAP (lo que el VM realmente manda/recibe) --"
grep -icE 'Discover|Offer|Request|Reply|BOOTP' /tmp/netdiag.pcap.txt; grep -iE 'Discover|Offer|cksum' /tmp/netdiag.pcap.txt | head -6
echo "-- paquetes DHCP capturados en $BR --"
grep -icE 'Discover|Offer|Request|Reply|BOOTP' /tmp/netdiag.pcap.txt
echo "-- muestra (Discover/Offer/checksum) --"
grep -iE 'Discover|Offer|cksum' /tmp/netdiag.pcap.txt | head -10
echo "-- dnsmasq: ¿recibió/ofreció? --"
grep -iE 'DHCPDISCOVER|DHCPOFFER|DHCPACK|no address' "$DNSLOG" 2>/dev/null | tail -8 || echo "(sin entradas DHCP)"

echo; echo "### 3. veredicto del diagnóstico ###"
SAW_DISC=$(grep -ic 'Discover' /tmp/netdiag.pcap.txt)
BAD_CKSUM=$(grep -ic 'bad udp cksum' /tmp/netdiag.pcap.txt)
DNS_SAW=$(grep -ic 'DHCPDISCOVER' "$DNSLOG" 2>/dev/null)
echo "DISCOVER en bridge=$SAW_DISC  bad-cksum=$BAD_CKSUM  dnsmasq-vio-DISCOVER=$DNS_SAW  input-drop=$INPUT_DROP"
if [ "$SAW_DISC" = 0 ]; then echo ">> el DISCOVER NO llega al bridge (problema tap/QEMU)"; fi
if [ "$SAW_DISC" != 0 ] && [ "$BAD_CKSUM" != 0 ]; then echo ">> DISCOVER llega con CHECKSUM MALO (offload) ⇒ dnsmasq lo descarta"; fi
if [ "$SAW_DISC" != 0 ] && [ "$DNS_SAW" = 0 ] && [ "$BAD_CKSUM" = 0 ]; then echo ">> DISCOVER llega OK pero dnsmasq no lo procesa ⇒ firewall INPUT (drop=$INPUT_DROP)"; fi

echo; echo "### 4. firewall INPUT: inspecciono, meto accepts CONTADOS y retesteo ###"
echo "-- inet filter input ANTES (con handles) --"
nft -a list chain inet filter input 2>/dev/null
echo "-- inserto accepts contados (por iif del bridge y por puerto DHCP/DNS) --"
nft insert rule inet filter input udp dport '{ 67, 68, 53 }' counter accept comment '"hmlab"' 2>&1 | head -2
nft insert rule inet filter input iifname "$BR" counter accept comment '"hmlab"' 2>&1 | head -2
run_test
echo "-- reglas hmlab DESPUÉS del retest (los counters dicen cuál matcheó) --"
nft -a list chain inet filter input 2>/dev/null | grep -i hmlab
echo "-- dnsmasq tras retest --"
grep -iE 'DHCPDISCOVER|DHCPOFFER|DHCPACK' "$DNSLOG" 2>/dev/null | tail -5 || echo "(nada)"
echo "-- netup tras retest --"
grep -aE 'netup: lease|netup: red configurada|sin respuesta DHCP|PING_OK|PING_FAIL|DNS_OK|DNS_FAIL' work/netdiag-run.log | tail -5
if grep -qa 'netup: red configurada' work/netdiag-run.log; then echo "RESULTADO: ✓ RED OK"; else echo "RESULTADO: ✗ sigue fallando"; fi

echo; echo "### 5. dnsmasq log COMPLETO (volcado para análisis) ###"
tail -30 "$DNSLOG" 2>/dev/null || echo "(no legible)"
echo; echo "### 6. netup salida COMPLETA del retest ###"
tr -d '\r' < work/netdiag-run.log 2>/dev/null | sed 's/\x1b\[[0-9;?]*[a-zA-Z]//g' | grep -aE 'netup:|e1000.*Link|PING_|DNS_' | tail -12

chmod 644 "$OUT" 2>/dev/null
chmod 666 work/netdiag-run.log 2>/dev/null
echo; echo "(reporte: $OUT)"
