repositories / bugabinga.net
bugabinga.net
personal infrastructure for bugabinga!
owned by admin
scripts/remote/apply-valheim-relay.sh
Raw#!/usr/bin/env bash
set -euo pipefail
[[ "$#" -eq 1 && -f "$1" ]] || {
echo "usage: apply-valheim-relay.sh STAGED_FRAGMENT" >&2
exit 2
}
source_fragment="$1"
config=/etc/sysconfig/nftables.conf
fragment=/etc/nftables/valheim.nft
include_line="include \"${fragment}\""
work="$(mktemp -d /var/tmp/valheim-relay.XXXXXX)"
config_backup="${work}/nftables.conf.before"
fragment_backup="${work}/valheim.nft.before"
fragment_existed=false
changed=false
cleanup() {
local status=$?
if [[ "$status" -ne 0 && "$changed" = true ]]; then
cp -f "$config_backup" "$config" || true
if [[ "$fragment_existed" = true ]]; then
cp -f "$fragment_backup" "$fragment" || true
else
rm -f "$fragment" || true
fi
echo "Valheim relay persistence rolled back: ${config} ${fragment}" >&2
fi
if [[ "$status" -ne 0 ]]; then rm -rf "$work"; fi
rm -f "$source_fragment"
exit "$status"
}
trap cleanup EXIT
[[ -f "$config" ]] || {
echo "missing persistent nftables config: ${config}" >&2
exit 1
}
[[ "$(grep -Fc "$include_line" "$config" || true)" -le 1 ]] || {
echo "refusing duplicate Valheim nftables include in ${config}" >&2
exit 1
}
[[ "$(grep -c '^add rule ' "$source_fragment")" -eq 4 ]] || {
echo "invalid Valheim nftables fragment" >&2
exit 1
}
grep -q '^add rule inet filter forward .*bugabinga-valheim-forward-ipv4"$' "$source_fragment"
grep -q '^add rule inet filter forward .*bugabinga-valheim-forward-ipv6"$' "$source_fragment"
grep -q '^add rule ip nat prerouting .*bugabinga-valheim-dnat-ipv4"$' "$source_fragment"
grep -q '^add rule ip6 nat prerouting .*bugabinga-valheim-dnat-ipv6"$' "$source_fragment"
cp --preserve=mode "$config" "$config_backup"
if [[ -e "$fragment" ]]; then
cp --preserve=mode "$fragment" "$fragment_backup"
fragment_existed=true
fi
cp --preserve=mode "$config" "${work}/nftables.conf.candidate"
if ! grep -Fqx "$include_line" "${work}/nftables.conf.candidate"; then
printf '\n%s\n' "$include_line" >>"${work}/nftables.conf.candidate"
fi
cp "$source_fragment" "${work}/valheim.nft.candidate"
chmod 0644 "${work}/valheim.nft.candidate"
sed "s|$(printf '%s' "$include_line" | sed 's/[][\\/.^$*|]/\\&/g')|include \"${work}/valheim.nft.candidate\"|" "${work}/nftables.conf.candidate" >"${work}/nftables.conf.check"
nft --check --file "${work}/nftables.conf.check"
: >"${work}/live.batch"
for chain in 'inet filter forward' 'ip nat prerouting' 'ip6 nat prerouting'; do
read -r family table name <<<"$chain"
nft -a list chain "$family" "$table" "$name" |
awk -v family="$family" -v table="$table" -v chain="$name" '
/comment "bugabinga-valheim-(forward|dnat)-ipv[46]"/ {
if ($(NF-1) != "handle" || $NF !~ /^[0-9]+$/) exit 1
print "delete rule " family " " table " " chain " handle " $NF
}
' >>"${work}/live.batch"
done
cat "$source_fragment" >>"${work}/live.batch"
nft --check --file "${work}/live.batch"
install -d -m 0755 /etc/nftables
changed=true
install -m 0644 "${work}/valheim.nft.candidate" "$fragment"
cp --preserve=mode "${work}/nftables.conf.candidate" "$config"
nft --file "${work}/live.batch"
changed=false
printf '%s\n' "changed root paths: ${fragment} ${config}"
printf 'Rollback evidence retained at %s\n' "$work"
printf '%s\n' 'Valheim relay rules installed without nftables restart or ruleset flush.'