set -euo pipefail
action="${1:-}"; chain="${2:-}"
closeshow)$ && -n "$chain" || { echo "usage: $0 open|close|show <chain>" >&2; exit 2; }
env_file="/etc/soft3/$chain.env"
span> || { echo "missing $env_file" >&2; exit 2; }
source "$env_file"
port="${SOFT3_RADIO##*:}"
[[ "$port" =~ ^[0-9]+$ && "$port" -ge 1024 && "$port" -le 65535 ]] || { echo "SOFT3_RADIO has no sane port: '$SOFT3_RADIO'" >&2; exit 2; }
comment="soft3-chain-$chain-radio"
log="/var/log/soft3-chain/ufw.log"
mkdir -p "$(dirname "$log")"
present() { ufw status | grep -qE "^$port/udp\s+ALLOW IN\s+Anywhere" ; }
case "$action" in
show)
ufw status numbered | grep -E "$port/udp|$comment" || echo "no rule for $port/udp"
;;
open)
if present; then echo "already open: $port/udp ($chain)"; exit 0; fi
ufw allow proto udp to any port "$port" comment "$comment"
echo "$(date -u +%FT%TZ) open $port/udp $chain by $(logname 2>/dev/null || echo root)" >> "$log"
echo "opened $port/udp ($chain)"
;;
close)
if ! present; then echo "not open: $port/udp ($chain)"; exit 0; fi
ufw delete allow proto udp to any port "$port" comment "$comment" >/dev/null 2>&1 \
|| ufw delete allow "$port/udp"
echo "$(date -u +%FT%TZ) close $port/udp $chain by $(logname 2>/dev/null || echo root)" >> "$log"
echo "closed $port/udp ($chain)"
;;
esac