removing open ports when sibling project removed
This commit is contained in:
@@ -83,16 +83,33 @@ setup_cockpit() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Allow the services and ports in firewall.conf through firewalld's default
|
||||
# zone, then make sure firewalld is running. Only adds rules, never removes
|
||||
# them, so rules added by hand or by sibling projects stay. Safe to re-run.
|
||||
# Print the rules a firewall.conf asks for, one per line, as service:<name> or
|
||||
# port:<port>/<protocol>. Sourced in a subshell so the file can't change
|
||||
# anything else.
|
||||
firewall_entries() {
|
||||
(
|
||||
FIREWALL_SERVICES=()
|
||||
FIREWALL_PORTS=()
|
||||
source "$1" > /dev/null || exit 1
|
||||
for e in "${FIREWALL_SERVICES[@]}"; do echo "service:$e"; done
|
||||
for e in "${FIREWALL_PORTS[@]}"; do echo "port:$e"; done
|
||||
)
|
||||
}
|
||||
|
||||
# Rules setup_firewall opened, so it knows which ones it may close again
|
||||
FIREWALL_STATE="$HOME/.local/state/miniserver/firewall-opened"
|
||||
|
||||
# Allow what MiniServer's and each sibling project's firewall.conf ask for
|
||||
# through firewalld's default zone, and make sure firewalld is running.
|
||||
# Closes a rule only if setup_firewall opened it and no firewall.conf asks for
|
||||
# it any more (e.g. after `sibling remove`); rules that were already there or
|
||||
# were added by hand are left alone. Safe to re-run.
|
||||
setup_firewall() {
|
||||
command -v firewall-offline-cmd &> /dev/null || return 0
|
||||
source "$HOME/.local/share/MiniServer/firewall.conf"
|
||||
|
||||
# firewall-cmd only works while firewalld is running; before that, write the
|
||||
# permanent config directly so SSH is allowed before the firewall comes up
|
||||
local fw running=0 changed=0 svc port
|
||||
local fw running=0 changed=0 complete=1 status=0
|
||||
if systemctl is-active --quiet firewalld; then
|
||||
running=1
|
||||
fw=(sudo firewall-cmd --permanent)
|
||||
@@ -100,39 +117,86 @@ setup_firewall() {
|
||||
fw=(sudo firewall-offline-cmd)
|
||||
fi
|
||||
|
||||
# Keep SSH reachable if sshd listens on a port other than 22
|
||||
local ports=("${FIREWALL_PORTS[@]}")
|
||||
local wanted=() opened=() kept=() conf out entry kind value port
|
||||
for conf in "$HOME/.local/share/MiniServer/firewall.conf" "$HOME/.local/share/siblings/"*/firewall.conf; do
|
||||
[ -f "$conf" ] || continue
|
||||
if out="$(firewall_entries "$conf")"; then
|
||||
[ -n "$out" ] && mapfile -t -O "${#wanted[@]}" wanted <<< "$out"
|
||||
else
|
||||
echo "Firewall: could not read $conf, so no rules will be closed this time."
|
||||
complete=0
|
||||
status=1
|
||||
fi
|
||||
done
|
||||
|
||||
# Keep SSH reachable if sshd listens on a port other than 22. If its config
|
||||
# can't be read, don't close anything: that port could be the SSH port.
|
||||
if command -v sshd &> /dev/null; then
|
||||
for port in $(sudo sshd -T 2> /dev/null | awk '$1 == "port" && $2 != 22 { print $2 }'); do
|
||||
ports+=("$port/tcp")
|
||||
done
|
||||
if out="$(sudo sshd -T 2> /dev/null)"; then
|
||||
for port in $(awk '$1 == "port" && $2 != 22 { print $2 }' <<< "$out"); do
|
||||
wanted+=("port:$port/tcp")
|
||||
done
|
||||
else
|
||||
complete=0
|
||||
fi
|
||||
fi
|
||||
|
||||
for svc in "${FIREWALL_SERVICES[@]}"; do
|
||||
if ! "${fw[@]}" --query-service="$svc" &> /dev/null; then
|
||||
echo "Firewall: allowing $svc"
|
||||
"${fw[@]}" --add-service="$svc"
|
||||
changed=1
|
||||
[ -f "$FIREWALL_STATE" ] && mapfile -t opened < "$FIREWALL_STATE"
|
||||
|
||||
for entry in "${wanted[@]}"; do
|
||||
kind="${entry%%:*}"
|
||||
value="${entry#*:}"
|
||||
if ! { [[ "$kind" == service && "$value" =~ ^[A-Za-z0-9_.-]+$ ]] ||
|
||||
[[ "$kind" == port && "$value" =~ ^[0-9]+(-[0-9]+)?/(tcp|udp|sctp|dccp)$ ]]; }; then
|
||||
echo "Firewall: ignoring invalid $kind '$value'"
|
||||
status=1
|
||||
continue
|
||||
fi
|
||||
if ! "${fw[@]}" --query-"$kind"="$value" &> /dev/null; then
|
||||
echo "Firewall: allowing $value"
|
||||
if "${fw[@]}" --add-"$kind"="$value"; then
|
||||
opened+=("$entry")
|
||||
changed=1
|
||||
else
|
||||
status=1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
for port in "${ports[@]}"; do
|
||||
if ! "${fw[@]}" --query-port="$port" &> /dev/null; then
|
||||
echo "Firewall: allowing $port"
|
||||
"${fw[@]}" --add-port="$port"
|
||||
changed=1
|
||||
|
||||
for entry in "${opened[@]}"; do
|
||||
[ -n "$entry" ] || continue
|
||||
if (( ! complete )) || printf '%s\n' "${wanted[@]}" | grep -qxF -- "$entry"; then
|
||||
kept+=("$entry")
|
||||
continue
|
||||
fi
|
||||
kind="${entry%%:*}"
|
||||
value="${entry#*:}"
|
||||
if "${fw[@]}" --query-"$kind"="$value" &> /dev/null; then
|
||||
echo "Firewall: closing $value (nothing asks for it any more)"
|
||||
if "${fw[@]}" --remove-"$kind"="$value"; then
|
||||
changed=1
|
||||
else
|
||||
kept+=("$entry")
|
||||
status=1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
mkdir -p "$(dirname "$FIREWALL_STATE")"
|
||||
printf '%s\n' "${kept[@]}" | sed '/^$/d' | sort -u > "$FIREWALL_STATE"
|
||||
|
||||
if (( running )); then
|
||||
if (( changed )); then
|
||||
sudo firewall-cmd --reload
|
||||
sudo firewall-cmd --reload || status=1
|
||||
fi
|
||||
else
|
||||
echo "Starting firewalld..."
|
||||
sudo systemctl enable --now firewalld
|
||||
sudo systemctl enable --now firewalld || status=1
|
||||
# Docker sets up its firewalld zone only when it starts
|
||||
if systemctl is-active --quiet docker; then
|
||||
echo "Docker started before firewalld. Restart it (sudo systemctl restart docker) or reboot so its containers' ports work through the firewall."
|
||||
fi
|
||||
fi
|
||||
|
||||
return $status
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user