🔥 Sync 2026-10-24 23:19:23

This commit is contained in:
github-actions[bot] committed 2026-10-24 23:19:23 +08:00
1 parent 9886197604
commit 37e1475e87
59 files changed
+5167 -1483

No files matched your search

@@ -0,0 +1,87 @@
#!/bin/sh
# Background worker for the "Auto Configure Firewall" action.
#
# Kept outside the rpcd plugin on purpose: the RPC must return before the
# network is reloaded, otherwise a request coming through the network being
# reloaded (reverse proxy, or LuCI over Tailscale itself) dies with an XHR
# abort and the user cannot tell whether anything happened.
#
# The status file is line based rather than JSON so that a message containing
# a backslash, a quote or a tab cannot corrupt it: whoever reads it builds the
# JSON itself. Line 4 is the run id handed over by the RPC, so a result from a
# previous run can never be mistaken for this one.
#
# Usage: tailscale-setup-firewall <run-id>
STATE_FILE=/var/run/tailscale-fwsetup.status
LOCK_FILE=/var/run/tailscale-fwsetup.lock
RUN_ID="$1"
write_state() {
{
printf '%s\n' "$1"
printf '%s\n' "$2"
# one line only: the reader takes fixed line numbers, so a message that
# wrapped would shift the run id off the last line. tr cannot strip a
# real newline, sed can.
if [ -n "$3" ]; then
printf '%s' "$3" | sed -e 's/\r//g' -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'
fi
printf '\n'
printf '%s\n' "$RUN_ID"
} > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
}
# Only one worker at a time: a second click while a reload is running would
# queue another network reload on top of an unfinished one. mkdir is atomic and
# is the only portable primitive available here; a test-then-write pair lets
# two workers through at the same moment. Stale locks are recognised by age so
# a recycled pid or a killed worker cannot block forever.
LOCK_DIR="$LOCK_FILE.d"
lock_age() {
local ts now
ts=$(cat "$LOCK_DIR/ts" 2>/dev/null)
case "$ts" in ''|*[!0-9]*) echo 999999; return ;; esac
now=$(date +%s)
echo $((now - ts))
}
if ! mkdir "$LOCK_DIR" 2>/dev/null; then
if [ "$(lock_age)" -gt 300 ]; then
# the holder is gone; take the lock over
rm -rf "$LOCK_DIR"
mkdir "$LOCK_DIR" 2>/dev/null || exit 0
else
# someone else is already reloading: say so instead of leaving the
# status file at "queued" and letting the UI time out
write_state busy locked "Another firewall reload is already running"
exit 0
fi
fi
echo "$$" > "$LOCK_DIR/pid"
date +%s > "$LOCK_DIR/ts"
trap 'write_state failed aborted "Worker terminated unexpectedly"; rm -rf "$LOCK_DIR"' EXIT HUP INT TERM
write_state running network "Reloading network"
if ! /etc/init.d/network reload >/dev/null 2>&1; then
write_state failed network "Network reload failed"
trap - EXIT HUP INT TERM
rm -rf "$LOCK_DIR"
exit 1
fi
write_state running firewall "Reloading firewall"
if ! /etc/init.d/firewall reload >/dev/null 2>&1; then
write_state failed firewall "Firewall reload failed"
trap - EXIT HUP INT TERM
rm -rf "$LOCK_DIR"
exit 1
fi
write_state done done "Firewall configuration applied"
trap - EXIT HUP INT TERM
rm -rf "$LOCK_DIR"