tests: soak gate via uploaded helper (quoting), 04/05 assertions fixed (pf interface name vs OS device)

This commit is contained in:
lgcosta committed 2026-11-11 19:59:27 -03:00
1 parent 3aa0c2d0d0
commit 18c0a69f74
4 files changed
+45 -26

No files matched your search

+1 -1
View File
@@ -34,7 +34,7 @@ ANC=$(pfput /tmp/g4anc.conf) || { bad "anchor conf upload"; finish; }
pf0 "/opt/pf/pfctl -a restricted -f $ANC" || { bad "anchor ruleset load"; finish; }
pf0 '/opt/pf/pfctl -sr' | grep -q 'anchor "restricted"' && ok "anchor rule in main ruleset" || bad "anchor rule missing"
pf0 '/opt/pf/pfctl -a restricted -sr' | grep -q 'keep state' && ok "anchor rules listed" || bad "anchor rules missing"
pf0 '/opt/pf/pfctl -a restricted -sr' | grep -q 'pass in quick proto icmp' && ok "anchor rules listed" || bad "anchor rules missing"
# the request must pass through the anchor (the block rule would drop it)
cli "ping -c2 -W2 $SRV_IP >/dev/null 2>&1" && ok "anchor pass honoured (request allowed)" \
+5 -3
View File
@@ -9,7 +9,9 @@
set -uo pipefail; cd "$(dirname "$0")"; . ./lib.sh
FAILED=0
EGRESS_IP=$(pf0 'ip -4 addr show egress | grep -o "inet [0-9.]*" | head -1 | cut -d" " -f2')
# pf calls the interface "egress"; the OS names it ethX - resolve both
EGRESS_DEV=$(pf0 "ip route get 8.8.8.8 | grep -o 'dev [a-z0-9]*' | cut -d' ' -f2")
EGRESS_IP=$(pf0 "ip -4 addr show $EGRESS_DEV | grep -o 'inet [0-9.]*' | head -1 | cut -d' ' -f2")
[ -n "$EGRESS_IP" ] || EGRESS_IP=192.168.122.8
pf0 'insmod /opt/pf/pf.ko 2>/dev/null || insmod /tmp/pf.ko; true'
@@ -23,7 +25,7 @@ C
pfload /tmp/g05.conf || { bad "nat rule load"; finish; }
pf0 '/opt/pf/pfctl -sr' | grep -q 'nat-to' && ok "nat-to rule listed" || bad "nat-to not listed"
pf0 'tcpdump -ni egress -c 4 -e icmp > /tmp/nat.td 2>&1 &'
pf0 "tcpdump -ni $EGRESS_DEV -c 4 -e icmp > /tmp/nat.td 2>&1 &"
sleep 1
cli "ping -c2 -W2 $SRV_IP >/dev/null 2>&1" && ok "transit ping through NAT" || bad "transit ping"
sleep 2
@@ -36,6 +38,6 @@ else
fi
echo "$TD" | grep -q "$EGRESS_IP" && ok "egress source is $EGRESS_IP" || bad "egress source not seen"
pf0 '/opt/pf/pfctl -ss' | grep -q "$SRV_IP" && ok "state present" || bad "no state"
pf0 '/opt/pf/pfctl -ss' | grep -qi 'icmp' && ok "state present" || bad "no state"
pf0 '/opt/pf/pfctl -d' >/dev/null
finish
+24 -22
View File
@@ -1,50 +1,52 @@
#!/usr/bin/env bash
# M6 gate: soak + unload/leak discipline.
#
# 1) load pf, ruleset with states/tables/anchors, drive mixed traffic ~20s
# 1) load pf with a stateful ruleset, drive mixed traffic for ~20s
# 2) assert no BUG/WARNING/Oops in dmesg
# 3) disable, rmmod; assert module unloads cleanly (no refcount hang)
# 4) insmod/rmmod cycle x2; assert slab objects for pf caches return to the
# pre-load baseline (no leak), and that a reload works (timer/notifier
# re-registration is idempotent)
# 3) disable + rmmod: the module must unload cleanly (no refcount leak)
# 4) insmod/rmmod cycles: slab objects for the pf caches must return to the
# pre-load baseline (no leak) and a reload must work
set -uo pipefail; cd "$(dirname "$0")"; . ./lib.sh
FAILED=0
slab_snapshot() {
pf0 "grep -E '^(pf|pfk)' /proc/slabinfo | awk '{print \$1, \$3}'" | sort
}
HELPER=$(pfput ./soak-helper.sh) || { bad "helper upload"; finish; }
pf0 "chmod +x $HELPER" >/dev/null
pf0 'insmod /tmp/pf.ko 2>/dev/null || insmod /opt/pf/pf.ko; true'
pf0 'insmod /opt/pf/pf.ko 2>/dev/null || insmod /tmp/pf.ko; true'
pf0 '/opt/pf/pfctl -e; /opt/pf/pfctl -f /dev/null' >/dev/null
BEFORE=$(slab_snapshot)
BEFORE=$(pf0 "$HELPER slab")
cat > /tmp/g14.conf <<C
table <peers> { $CLI_IP }
anchor "s"
pass in quick on ingress proto icmp from <peers> keep state
pass out quick proto icmp keep state
pass out quick on egress proto icmp keep state
pass out quick proto tcp from any to any port 22 keep state
C
pfload /tmp/g14.conf || { bad soak ruleset; finish; }
pfload /tmp/g14.conf || { bad "soak ruleset"; finish; }
# mixed traffic: ICMP + TCP handshakes, 20s
cli "ping -q -c 30 -i 0.2 $SRV_IP >/dev/null 2>&1 &" 2>/dev/null
# mixed traffic: ICMP + TCP handshakes for ~20s
cli "ping -q -c 60 -i 0.3 $SRV_IP >/dev/null 2>&1 &" 2>/dev/null
cli "for i in 1 2 3 4 5; do nc -w1 -z $SRV_IP 22; done" 2>/dev/null
sleep 22
ST=$(pf0 '/opt/pf/pfctl -s states | wc -l')
ST=$(pf0 "$HELPER states")
[ "${ST:-0}" -ge 1 ] && ok "states under load ($ST)" || bad "no states under load"
DMESG=$(pf0 "dmesg | grep -cE 'BUG:|WARNING:|Oops|general protection'")
[ "${DMESG:-1}" = 0 ] && ok "no kernel BUG/WARN/Oops" || bad "dmesg anomalies ($DMESG)"
ANOM=$(pf0 "$HELPER dmesg")
if [ -z "$ANOM" ]; then
ok "no kernel BUG/WARN/Oops"
else
bad "dmesg anomalies:"
printf '%s\n' "$ANOM" | sed 's/^/ /'
fi
pf0 '/opt/pf/pfctl -d; /opt/pf/pfctl -f /dev/null' >/dev/null
pf0 'rmmod pf && echo UNLOAD_OK' | grep -q UNLOAD_OK && ok "clean unload (refcounts released)" || bad "rmmod failed"
sleep 1
pf0 'insmod /tmp/pf.ko 2>/dev/null || insmod /opt/pf/pf.ko; true; (/opt/pf/pfctl -s info >/dev/null && echo RELOAD_OK)' | grep -q RELOAD_OK && ok "reload after unload" || bad "reload failed"
pf0 'insmod /opt/pf/pf.ko 2>/dev/null || insmod /tmp/pf.ko; true; (/opt/pf/pfctl -s info >/dev/null && echo RELOAD_OK)' \
| grep -q RELOAD_OK && ok "reload after unload" || bad "reload failed"
pf0 'rmmod pf && echo UNLOAD_OK2' | grep -q UNLOAD_OK2 && ok "second unload" || bad "second rmmod"
sleep 1
AFTER=$(slab_snapshot)
# compare per-cache object counts if they exist on both sides
AFTER=$(pf0 "$HELPER slab")
LEAK=$(join <(echo "$BEFORE") <(echo "$AFTER") 2>/dev/null | awk '$3-$2 > 0 {print $1, $3-$2}')
if [ -n "$LEAK" ]; then bad "slab growth after cycles: $LEAK"; else ok "no slab growth after unload cycles"; fi
finish
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env bash
# Helper executed ON pf0 by 14-soak.sh (uploaded with pfput to avoid quoting
# hell through two ssh hops).
# $1 = "slab" | "dmesg" | "states"
case "${1:-}" in
slab)
grep -E '^(pf|pfk)' /proc/slabinfo | tr -s ' ' | cut -d' ' -f1,3 | sort
;;
dmesg)
dmesg | grep -E 'BUG:|WARNING:|Oops|general protection|kernel BUG' || true
;;
states)
/opt/pf/pfctl -s states 2>/dev/null | grep -c 'icmp' || true
;;
esac