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 -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 -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) # 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)" \ 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 set -uo pipefail; cd "$(dirname "$0")"; . ./lib.sh
FAILED=0 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 [ -n "$EGRESS_IP" ] || EGRESS_IP=192.168.122.8
pf0 'insmod /opt/pf/pf.ko 2>/dev/null || insmod /tmp/pf.ko; true' 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; } 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 '/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 sleep 1
cli "ping -c2 -W2 $SRV_IP >/dev/null 2>&1" && ok "transit ping through NAT" || bad "transit ping" cli "ping -c2 -W2 $SRV_IP >/dev/null 2>&1" && ok "transit ping through NAT" || bad "transit ping"
sleep 2 sleep 2
@@ -36,6 +38,6 @@ else
fi fi
echo "$TD" | grep -q "$EGRESS_IP" && ok "egress source is $EGRESS_IP" || bad "egress source not seen" 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 pf0 '/opt/pf/pfctl -d' >/dev/null
finish finish
+24 -22
View File
@@ -1,50 +1,52 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# M6 gate: soak + unload/leak discipline. # 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 # 2) assert no BUG/WARNING/Oops in dmesg
# 3) disable, rmmod; assert module unloads cleanly (no refcount hang) # 3) disable + rmmod: the module must unload cleanly (no refcount leak)
# 4) insmod/rmmod cycle x2; assert slab objects for pf caches return to the # 4) insmod/rmmod cycles: slab objects for the pf caches must return to the
# pre-load baseline (no leak), and that a reload works (timer/notifier # pre-load baseline (no leak) and a reload must work
# re-registration is idempotent)
set -uo pipefail; cd "$(dirname "$0")"; . ./lib.sh set -uo pipefail; cd "$(dirname "$0")"; . ./lib.sh
FAILED=0 HELPER=$(pfput ./soak-helper.sh) || { bad "helper upload"; finish; }
slab_snapshot() { pf0 "chmod +x $HELPER" >/dev/null
pf0 "grep -E '^(pf|pfk)' /proc/slabinfo | awk '{print \$1, \$3}'" | sort
}
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 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 cat > /tmp/g14.conf <<C
table <peers> { $CLI_IP } table <peers> { $CLI_IP }
anchor "s"
pass in quick on ingress proto icmp from <peers> keep state 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 pass out quick proto tcp from any to any port 22 keep state
C C
pfload /tmp/g14.conf || { bad soak ruleset; finish; } pfload /tmp/g14.conf || { bad "soak ruleset"; finish; }
# mixed traffic: ICMP + TCP handshakes, 20s # mixed traffic: ICMP + TCP handshakes for ~20s
cli "ping -q -c 30 -i 0.2 $SRV_IP >/dev/null 2>&1 &" 2>/dev/null 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 cli "for i in 1 2 3 4 5; do nc -w1 -z $SRV_IP 22; done" 2>/dev/null
sleep 22 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" [ "${ST:-0}" -ge 1 ] && ok "states under load ($ST)" || bad "no states under load"
DMESG=$(pf0 "dmesg | grep -cE 'BUG:|WARNING:|Oops|general protection'") ANOM=$(pf0 "$HELPER dmesg")
[ "${DMESG:-1}" = 0 ] && ok "no kernel BUG/WARN/Oops" || bad "dmesg anomalies ($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 '/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" pf0 'rmmod pf && echo UNLOAD_OK' | grep -q UNLOAD_OK && ok "clean unload (refcounts released)" || bad "rmmod failed"
sleep 1 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" pf0 'rmmod pf && echo UNLOAD_OK2' | grep -q UNLOAD_OK2 && ok "second unload" || bad "second rmmod"
sleep 1 sleep 1
AFTER=$(slab_snapshot) AFTER=$(pf0 "$HELPER slab")
# compare per-cache object counts if they exist on both sides
LEAK=$(join <(echo "$BEFORE") <(echo "$AFTER") 2>/dev/null | awk '$3-$2 > 0 {print $1, $3-$2}') 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 if [ -n "$LEAK" ]; then bad "slab growth after cycles: $LEAK"; else ok "no slab growth after unload cycles"; fi
finish 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