box-firewall: converge the UFW carve-out off the live bridge; fail closed at boot
The UFW block was create-once: gated on 'a DENY on boxnet exists', it pinned every UFW host to the gateway of the FIRST run. A bridge remapped off a colliding subnet (#80's escape hatch) kept its stale 'allow ... to <old-gw> port 53' and never gained the live gateway's, so box->gateway DNS died at box's own deny — the exact stale-carve-out failure #86 rewrote the ACL path to prevent, left standing in the UFW path (#86 review, item 1). The allows now converge on every run: DNS allows aimed anywhere but the live gateway are deleted, then the live set is ensured (ufw skips existing rules, so a fresh host gets the identical five rules and a re-run is a no-op). And the boot fallback GW=10.88.0.1 is gone (#86 review, item 2): with the bridge not yet addressed when the service ran, a BOX_SUBNET host got its carve-out built — and, once converging, converged — for the WRONG gateway, a latent DNS drop. Fail closed instead: an unaddressed bridge leaves the persisted UFW rules exactly as they are (they survive boots on their own, and nothing else in this script needs the gateway — the nft carve-out is interface-scoped) and says so on stderr; the next setup-host run or service restart converges them once the bridge is up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
a4d6388b02
commit
ca1a759f3a
1 changed files with 24 additions and 5 deletions
|
|
@ -9,15 +9,34 @@ NET=boxnet
|
|||
# The gateway is read off the live bridge, not hardcoded: the subnet is an
|
||||
# input now (BOX_SUBNET, setup-host.sh — #80), and a bridge moved off a
|
||||
# colliding subnet must keep its firewall. setup-host runs us after the
|
||||
# bridge exists, so the live read is the truth at install time; UFW rules
|
||||
# persist across boots on their own, so the default only papers over the
|
||||
# no-bridge-yet window at boot on a default-subnet host.
|
||||
# bridge exists, so the live read is the truth at install time. At boot the
|
||||
# bridge may not be addressed yet — then GW is EMPTY and the UFW carve-out
|
||||
# below is left alone rather than built for a guessed gateway: the old
|
||||
# GW=10.88.0.1 fallback was wrong on every BOX_SUBNET host that hit the
|
||||
# no-bridge window, a latent DNS drop (#86 review). Failing closed costs
|
||||
# nothing: UFW rules persist across boots on their own, and nothing else in
|
||||
# this script needs the gateway (the nft carve-out is interface-scoped).
|
||||
# ('|| true': under pipefail an absent bridge would kill the script here.)
|
||||
GW="$(ip -4 -o addr show dev "$NET" 2>/dev/null | awk '{ split($4, a, "/"); print a[1]; exit }' || true)"
|
||||
[ -n "$GW" ] || GW=10.88.0.1
|
||||
|
||||
if command -v ufw >/dev/null && ufw status 2>/dev/null | grep -q "Status: active"; then
|
||||
if ! ufw status | grep "on $NET" | grep -q "DENY"; then
|
||||
if [ -z "$GW" ]; then
|
||||
echo "box-firewall: $NET has no address yet — UFW DNS carve-out left as-is (no rule beats a wrong one; the persisted rules survive boots, and setup-host or a service restart converges them once the bridge is addressed)" >&2
|
||||
else
|
||||
# Converge, don't create-once (the ACL's own #86 lesson, applied to UFW):
|
||||
# gating this block on "a DENY on boxnet exists" pinned every host to the
|
||||
# gateway of the FIRST run — a bridge remapped off a colliding subnet
|
||||
# (#80's escape hatch) kept its stale 'allow … to <old-gw> port 53' and
|
||||
# never gained the live gateway's, so box→gateway DNS died at our own
|
||||
# deny while every config looked right. Drop the DNS allows aimed
|
||||
# anywhere else, then ensure the live set: ufw skips a rule that already
|
||||
# exists, so the re-run is a no-op and a fresh host gets exactly the
|
||||
# rules it always did.
|
||||
for stale in $(ufw status | awk -v net="$NET" -v gw="$GW" '
|
||||
$2 ~ /^53\// && $3 == "on" && $4 == net && $1 != gw { print $1 }' | sort -u); do
|
||||
ufw delete allow in on "$NET" to "$stale" port 53 proto tcp || true
|
||||
ufw delete allow in on "$NET" to "$stale" port 53 proto udp || true
|
||||
done
|
||||
ufw insert 1 deny in on "$NET"
|
||||
ufw insert 1 allow in on "$NET" to "$GW" port 53 proto tcp
|
||||
ufw insert 1 allow in on "$NET" to "$GW" port 53 proto udp
|
||||
|
|
|
|||
Loading…
Reference in a new issue