🎈 Sync 2026-10-04 14:38:18

This commit is contained in:
github-actions[bot] committed 2026-10-04 14:38:18 +08:00
1 parent 0e6611f767
commit aba12667c5
88 files changed
+4600 -1458

No files matched your search

@@ -118,6 +118,86 @@ OUT="$STAGE/rendered.nft"
ERR="$STAGE/render.err"
trap '[ "$OWN_STAGE" = 1 ] && rm -rf "$STAGE"' EXIT INT TERM
# --- the node-address bypass is not gated on the literal-address file ------
#
# This is a source-level check, not a render one, on purpose. The render layer
# below is skipped wherever firewall4 is absent - which is every off-target
# run - and the failure this pins is one that renders perfectly and does
# nothing: with a host-name node there are no literal addresses, so a set and
# rules gated on "the literal list is non-empty" simply are not emitted, and
# dnsmasq's nftset= back-fill has no set to land in. r41 shipped that.
#
# The invariant, stated so it can be grepped: `node_addr_v4` may guard the
# `elements = { ... }` line and nothing else. Deciding whether the set and the
# return rules exist at all belongs to node_protect, which is true when either
# export file has content.
if ! grep -q 'function node_addr_protected(run_dir)' "$TEMPLATE_SRC"; then
echo "FAIL: firewall_post.ut has no node_addr_protected(); the node bypass cannot"
echo " distinguish 'nothing to protect' from 'a host name dnsmasq will resolve'"
FAILED=1
else
np_body="$(sed -n '/function node_addr_protected(run_dir)/,/^}/p' "$TEMPLATE_SRC")"
for f in node-addr-ips.txt node-addr-domains.txt; do
if ! printf '%s' "$np_body" | grep -q "$f"; then
echo "FAIL: node_addr_protected() does not look at $f"
FAILED=1
fi
done
[ "$FAILED" -eq 0 ] && echo "PASS: node_addr_protected() covers both export files"
fi
# Both helpers read run_dir, and they are defined ~80 lines above its
# declaration. In this ucode a closure captures the block variables that exist
# where the function is DEFINED, so a function defined earlier cannot see a
# const declared later - the call fails with "access to undeclared variable
# run_dir" while run_dir sits right there in the file. Passing it in is the
# only spelling that works, and r43 is what proved it.
for fn in node_addr_protected node_addr_to_nftarr; do
if ! grep -q "function $fn(run_dir" "$TEMPLATE_SRC"; then
echo "FAIL: $fn does not take run_dir as a parameter; in this ucode a closure only"
echo " sees block variables declared before the function definition, and both"
echo " helpers are defined above run_dir"
FAILED=1
fi
done
[ "$FAILED" -eq 0 ] && echo "PASS: the node-address helpers take run_dir as a parameter"
# Every consumer of the v4 set outside its own elements= line must be gated on
# node_protect. `node_addr_v4)` as a condition is exactly the mistake.
stray_gate="$(awk '
/if \(node_addr_v4/ {
# The one legitimate use guards the elements= line that follows it.
saw = 1; ln = NR; next
}
saw {
if ($0 ~ /elements *= *\{/) { saw = 0; next }
print " " ln ": " $0
saw = 0
}
' "$TEMPLATE_SRC" || true)"
if [ -n "$stray_gate" ]; then
echo "FAIL: the node-address set is gated on node_addr_v4 having elements; a host-name"
echo " node has none, and the set plus its return rules then never exist:"
printf ' %s\n' "$stray_gate"
FAILED=1
fi
# And the return rules themselves must be present in all three chains, each
# behind node_protect rather than behind a literal-address list.
for chain in redirect mangle_prerouting mangle_output; do
if ! grep -q "$chain" "$TEMPLATE_SRC"; then
echo "FAIL: chain $chain disappeared from firewall_post.ut"
FAILED=1
fi
done
v4_rules="$(grep -c 'ip daddr @homeproxy_node_addr_v4 counter return' "$TEMPLATE_SRC" || true)"
if [ "$v4_rules" -eq 3 ]; then
echo "PASS: all three chains carry the node-address return rule"
else
echo "FAIL: expected 3 'ip daddr @homeproxy_node_addr_v4 counter return' rules, found $v4_rules"
FAILED=1
fi
# Probe with ucode, not utpl: `utpl -e` is not an eval flag, it renders the
# argument as template text and always succeeds.
if ! ucode -e 'require("fw4");' > "/dev/null" 2>&1; then