mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 19:07:04 +01:00
wg firewall: allow-workout-poke opens tcp/8773 from the LAN only (ALLOW_WORKOUT_POKE)
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
screen-locker's workout-poke.service takes the phone's POST of a finished workout on tcp/8773. The flag is persisted like ALLOW_DOT so every re-apply keeps it, and there is deliberately no wg0 rule: off the home LAN the poke fails fast and the normal sync credits the workout instead. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018RHwVPyiiQMPh4M3JQwQku
This commit is contained in:
parent
8bcdd20915
commit
20e05f021f
@ -0,0 +1,15 @@
|
||||
{
|
||||
"title": "Firewall: LAN-only tcp/8773 for the workout poke",
|
||||
"objective": "setup_wireguard_ssh.sh allow-workout-poke opens tcp/8773 from the LAN subnet only (never wg0), persists ALLOW_WORKOUT_POKE so every later re-apply keeps it, and leaves it closed when the flag is unset or false.",
|
||||
"acceptance_criteria": [
|
||||
"ALLOW_WORKOUT_POKE unset or false renders no dport 8773 rule (test_wg_firewall.sh)",
|
||||
"ALLOW_WORKOUT_POKE=true renders exactly one 8773 rule: ip saddr ${LAN_SUBNET} tcp dport 8773 accept (test_wg_firewall.sh)",
|
||||
"allow_workout_poke saves the flag as true before verify-then-apply, and the applied ruleset carries the rule (test_wg_firewall.sh)",
|
||||
"Host: nft list ruleset shows the rule after the user ran allow-workout-poke"
|
||||
],
|
||||
"out_of_scope": [
|
||||
"Any wg0 rule for 8773",
|
||||
"The poke server itself (screen-locker repo)"
|
||||
],
|
||||
"verifier": "lib/tests/test_wg_firewall.sh, lib/tests/run_all.sh in shell_coverage_jail.sh, nft list ruleset on the host"
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
{
|
||||
"intent": "screen-locker's workout poke (phone POSTs a finished workout to tcp/8773) can reach the PC from the home LAN, persisted across firewall re-applies, without exposing the port on WireGuard.",
|
||||
"scope": [
|
||||
"linux_configuration/features/lib/wg_firewall.sh: ALLOW_WORKOUT_POKE renders 'ip saddr ${LAN_SUBNET} tcp dport 8773 accept'; allow_workout_poke()",
|
||||
"linux_configuration/features/setup_wireguard_ssh.sh: default, save_config, require_root list, allow-workout-poke dispatch",
|
||||
"linux_configuration/features/lib/wg_sshd.sh: usage line",
|
||||
"linux_configuration/features/lib/tests/test_wg_firewall.sh: render + apply-path tests",
|
||||
"Non-goal: no wg0 rule for 8773; off the LAN the poke fails fast and the normal sync credits the workout"
|
||||
],
|
||||
"changes": [
|
||||
"New ALLOW_WORKOUT_POKE flag (default false) persisted in .wireguard_ssh.conf like ALLOW_DOT",
|
||||
"allow-workout-poke subcommand: export flag, save_config, render, verify-then-apply, install verify units"
|
||||
],
|
||||
"verification": [
|
||||
{
|
||||
"command": "bash linux_configuration/features/lib/tests/test_wg_firewall.sh",
|
||||
"result": "pass",
|
||||
"evidence": "18 passed, 0 failed: unset/false render no 8773 rule; true renders exactly one, LAN-only; allow_workout_poke saves the flag as true before applying and the applied ruleset carries the rule"
|
||||
},
|
||||
{
|
||||
"command": "shell_coverage_jail.sh --subject linux_configuration/features/lib/tests/run_all.sh <jail_args> --min 0 --fail-on-case-error",
|
||||
"result": "pass",
|
||||
"evidence": "jailed suite exit 0"
|
||||
},
|
||||
{
|
||||
"command": "sudo setup_wireguard_ssh.sh allow-workout-poke on the host (run by the user)",
|
||||
"result": "pass",
|
||||
"evidence": "nft list ruleset shows ip saddr <LAN> tcp dport 8773 accept in inet filter input"
|
||||
},
|
||||
{
|
||||
"command": "pre-commit run --files <the four files>",
|
||||
"result": "pass",
|
||||
"evidence": "all hooks passed"
|
||||
}
|
||||
],
|
||||
"risks": [
|
||||
"Any LAN host can reach tcp/8773; the poke server authenticates requests itself."
|
||||
],
|
||||
"rollback": [
|
||||
"git revert this commit, set ALLOW_WORKOUT_POKE=false in .wireguard_ssh.conf and re-run any allow-* to re-render",
|
||||
"After rollback: setup_wireguard_ssh.sh verify reports no drift and no 8773 rule"
|
||||
]
|
||||
}
|
||||
@ -63,8 +63,28 @@ if grep -q 'dport 853' "$RULES"; then
|
||||
else
|
||||
_t_pass "ALLOW_DOT=false renders no 853 rule"
|
||||
fi
|
||||
printf '\n-- the workout poke is LAN-only --\n'
|
||||
if grep -q 'dport 8773' "$RULES"; then
|
||||
_t_fail "ALLOW_WORKOUT_POKE unset renders no 8773 rule"
|
||||
else
|
||||
_t_pass "ALLOW_WORKOUT_POKE unset renders no 8773 rule"
|
||||
fi
|
||||
ALLOW_WORKOUT_POKE="true"
|
||||
render_nftables_ruleset "$RULES"
|
||||
_t_file_has "$RULES" 'ip saddr 192.168.1.0/24 tcp dport 8773 accept' \
|
||||
"ALLOW_WORKOUT_POKE opens 8773 to the LAN subnet"
|
||||
_t_eq "1" "$(grep -c 'dport 8773' "$RULES")" \
|
||||
"exactly one 8773 rule: no wg0 rule, the poke never rides WireGuard"
|
||||
ALLOW_WORKOUT_POKE="false"
|
||||
render_nftables_ruleset "$RULES"
|
||||
if grep -q 'dport 8773' "$RULES"; then
|
||||
_t_fail "ALLOW_WORKOUT_POKE=false renders no 8773 rule"
|
||||
else
|
||||
_t_pass "ALLOW_WORKOUT_POKE=false renders no 8773 rule"
|
||||
fi
|
||||
if command -v nft >/dev/null 2>&1; then
|
||||
ALLOW_DOT="true"
|
||||
ALLOW_WORKOUT_POKE="true"
|
||||
render_nftables_ruleset "$RULES"
|
||||
if nft -c -f "$RULES" >/dev/null 2>&1; then
|
||||
_t_pass "nft -c accepts the rendered ruleset"
|
||||
@ -100,4 +120,22 @@ else
|
||||
_t_pass "an inactive docker is not touched"
|
||||
fi
|
||||
|
||||
printf '\n-- allow-workout-poke persists the flag, then applies it --\n'
|
||||
# save_config belongs to setup_wireguard_ssh.sh and the apply needs root, so
|
||||
# both are recorded instead; the ruleset itself is the real render.
|
||||
save_config() {
|
||||
printf 'save_config ALLOW_WORKOUT_POKE=%s\n' "$ALLOW_WORKOUT_POKE" >>"$TEST_TMPDIR/calls.log"
|
||||
}
|
||||
verify_nftables_then_apply() { printf 'apply\n' >>"$TEST_TMPDIR/calls.log"; }
|
||||
: >"$TEST_TMPDIR/calls.log"
|
||||
rm -f "$NFT_CONF" "${NFT_CONF}.new"
|
||||
ALLOW_WORKOUT_POKE="false"
|
||||
out="$(allow_workout_poke 2>&1)"
|
||||
mapfile -t calls <"$TEST_TMPDIR/calls.log"
|
||||
_t_eq "save_config ALLOW_WORKOUT_POKE=true|apply" "$(IFS='|' && printf '%s' "${calls[*]}")" \
|
||||
"the flag is saved as true before the ruleset is applied"
|
||||
_t_file_has "${NFT_CONF}.new" 'ip saddr 192.168.1.0/24 tcp dport 8773 accept' \
|
||||
"the applied ruleset carries the LAN-only 8773 rule"
|
||||
_t_has "$out" 'not wg0' "the confirmation says the port stays off WireGuard"
|
||||
|
||||
_t_report "test_wg_firewall.sh"
|
||||
|
||||
@ -35,6 +35,14 @@ render_nftables_ruleset() {
|
||||
ha_rule=$'\n\t\tip saddr '"${LAN_SUBNET}"$' tcp dport 8123 accept'
|
||||
ha_rule+=$'\n\t\tiifname "'"${WG_IFACE}"$'" tcp dport 8123 accept'
|
||||
fi
|
||||
# Workout poke (screen-locker workout-poke.service): the phone POSTs a
|
||||
# finished workout to tcp/8773 the moment it ends. LAN only, deliberately
|
||||
# NO wg0 rule: off the home LAN the poke fails fast and the normal sync
|
||||
# credits the workout instead.
|
||||
local poke_rule=""
|
||||
if [[ ${ALLOW_WORKOUT_POKE:-false} == "true" ]]; then
|
||||
poke_rule=$'\n\t\tip saddr '"${LAN_SUBNET}"$' tcp dport 8773 accept'
|
||||
fi
|
||||
# DNS-over-TLS (setup_dot_resolver.sh, bound to the WireGuard address):
|
||||
# rendered here so a re-apply keeps it -- a runtime 'nft add rule' did not.
|
||||
local dot_rule=""
|
||||
@ -64,7 +72,7 @@ table inet filter {
|
||||
udp dport ${WG_PORT} accept
|
||||
|
||||
iifname "${WG_IFACE}" tcp dport 22 accept
|
||||
ip saddr ${LAN_SUBNET} tcp dport 22 accept${web_rule}${dns_rule}${ha_rule}${dot_rule}
|
||||
ip saddr ${LAN_SUBNET} tcp dport 22 accept${web_rule}${dns_rule}${ha_rule}${poke_rule}${dot_rule}
|
||||
}
|
||||
chain forward {
|
||||
type filter hook forward priority 0; policy drop;
|
||||
@ -171,3 +179,11 @@ allow_dot() {
|
||||
verify_nftables_then_apply
|
||||
log_ok "Opened tcp/853 on ${WG_IFACE} (persisted)."
|
||||
}
|
||||
|
||||
allow_workout_poke() {
|
||||
export ALLOW_WORKOUT_POKE=true
|
||||
save_config
|
||||
write_nftables_ruleset
|
||||
verify_nftables_then_apply
|
||||
log_ok "Opened tcp/8773 from ${LAN_SUBNET:-the LAN} only, not ${WG_IFACE} (persisted)."
|
||||
}
|
||||
|
||||
@ -236,6 +236,7 @@ Commands:
|
||||
allow-web Open tcp/80 and tcp/443 in the firewall (for a web server on this host).
|
||||
allow-dns Open udp/tcp 53 from the LAN in the firewall (for the DNS blocker on this host).
|
||||
allow-dot Open tcp/853 on wg0 in the firewall (for the DoT resolver on this host).
|
||||
allow-workout-poke Open tcp/8773 from the LAN only (screen-locker's workout poke).
|
||||
verify Check /etc/nftables.conf matches this script and that
|
||||
the live forward chain still lets Docker through.
|
||||
install-verify Install the units that run 'verify' at every boot, so
|
||||
|
||||
@ -41,6 +41,7 @@ export ALLOW_WEB="${ALLOW_WEB:-false}"
|
||||
export ALLOW_DNS="${ALLOW_DNS:-false}"
|
||||
export ALLOW_HOMEASSISTANT="${ALLOW_HOMEASSISTANT:-false}"
|
||||
export ALLOW_DOT="${ALLOW_DOT:-false}"
|
||||
export ALLOW_WORKOUT_POKE="${ALLOW_WORKOUT_POKE:-false}"
|
||||
|
||||
die() {
|
||||
log_error "$1"
|
||||
@ -56,6 +57,7 @@ ALLOW_WEB="${ALLOW_WEB}"
|
||||
ALLOW_DNS="${ALLOW_DNS}"
|
||||
ALLOW_HOMEASSISTANT="${ALLOW_HOMEASSISTANT}"
|
||||
ALLOW_DOT="${ALLOW_DOT}"
|
||||
ALLOW_WORKOUT_POKE="${ALLOW_WORKOUT_POKE}"
|
||||
EOF
|
||||
chmod 600 "$CONFIG_FILE"
|
||||
}
|
||||
@ -95,7 +97,7 @@ main() {
|
||||
# off -- exec sudo "$0" "$@" inside require_root must re-launch with the
|
||||
# subcommand still present, or sudo would silently run with no args.
|
||||
case "$cmd" in
|
||||
setup | add-peer | revoke | allow-web | allow-dns | allow-homeassistant | allow-dot | verify | install-verify)
|
||||
setup | add-peer | revoke | allow-web | allow-dns | allow-homeassistant | allow-dot | allow-workout-poke | verify | install-verify)
|
||||
require_root "$@"
|
||||
;;
|
||||
esac
|
||||
@ -140,6 +142,10 @@ main() {
|
||||
allow_dot
|
||||
install_verify_units
|
||||
;;
|
||||
allow-workout-poke)
|
||||
allow_workout_poke
|
||||
install_verify_units
|
||||
;;
|
||||
verify)
|
||||
verify_nft
|
||||
;;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user