Firewall: Ports auch wieder zumachen

"firewall open" kannte nur eine Richtung. Wer die Event Console wieder
abschaltet oder einen Eintrag aus FW_EXTRA_PORTS streicht, behielt die
Freigabe - der Port stand offen, ohne dass noch etwas dahinter lauscht.

"firewall close" bietet an, was offen ist, zu diesem Aufbau gehoert und
gerade nicht gebraucht wird. Dazu zaehlen die bekannten Ports des Stacks
und alles, was "firewall open --apply" selbst geoeffnet hat; das merkt
sich firewall-opened.conf, damit ein gestrichener FW_EXTRA_PORTS-Eintrag
nicht in Vergessenheit geraet.

Drei Sicherungen, weil hier das Aussperren droht:

  - SSH wird nie geschlossen: Port 22, der Port aus "sshd -T" und der
    Port der laufenden Sitzung aus SSH_CONNECTION
  - fremde Freigaben bleiben unberuehrt - wer 3306 fuer seine Datenbank
    offen hat, behaelt sie
  - Sammelregeln wie "80,443/tcp" werden gemeldet statt geloescht, sonst
    faellt ein noch gebrauchter Port mit weg

Bei ufw wird bewusst nicht nach Regelnummern geloescht. Die Nummern
verschieben sich beim ersten Loeschen, und da je Port ein eigener
Aufruf erzeugt wird, haette der naechste die falsche Regel getroffen -
im Test waere so eine 443er-Freigabe gefallen. Geloescht wird ueber die
Regelangabe, bei nftables ueber den Handle, bei iptables mit derselben
Angabe, mit der die Regel eingetragen wurde.

Nebenbei: fw_state_del liess die Datei stehen, wenn der letzte Eintrag
entfernt wurde - "grep -v" liefert dann 1. Unter "set -e" brach damit
ausserdem der Ablauf ab, noch vor dem Neuladen der Firewall.

In der Oberflaeche liegt das unter Einstellungen > Firewall als
"Nicht mehr benoetigte Ports schliessen".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-20 20:40:02 +02:00
co-authored by Claude Opus 5
parent 59304ae02d
commit 06ae4807ba
4 changed files with 420 additions and 7 deletions
+1
View File
@@ -16,3 +16,4 @@ images/*
backup-jobs.conf
scripts/.h.sh
scripts/.harness.sh
firewall-opened.conf
+36 -1
View File
@@ -1997,6 +1997,41 @@ anlegt.
80 nicht: Let's Encrypt prüft die Domain von außen, eine Begrenzung lässt die
Ausstellung scheitern. Darauf weist der Bericht hin.
### Wieder zumachen
`firewall open` kennt nur eine Richtung. Schaltet man die Event Console wieder
ab oder streicht einen Eintrag aus `FW_EXTRA_PORTS`, bleibt die Freigabe
stehen – der Port ist offen, ohne dass noch etwas dahinter lauscht. Dafür gibt
es die Gegenrichtung:
```bash
./scripts/cmk-manage.sh firewall close # Kommandos nur anzeigen
sudo ./scripts/cmk-manage.sh firewall close --apply
```
Angeboten wird nur, was **offen ist, zu diesem Aufbau gehört und gerade nicht
gebraucht wird**. Dazu zählen die Ports aus der Tabelle oben und alles, was
`firewall open --apply` selbst geöffnet hat – das merkt sich das Werkzeug in
`firewall-opened.conf`, damit ein gestrichener `FW_EXTRA_PORTS`-Eintrag nicht
in Vergessenheit gerät.
Drei Sicherungen sind eingebaut:
| | |
|---|---|
| **SSH bleibt offen** | Port 22, der Port, auf dem `sshd` wirklich lauscht (aus `sshd -T`), und der Port der laufenden Sitzung (`SSH_CONNECTION`) |
| **Fremde Freigaben bleiben** | Wer 3306 für seine Datenbank offen hat, behält sie – geschlossen wird nur, was dieser Aufbau kennt |
| **Sammelregeln bleiben** | Eine Regel wie `80,443/tcp` deckt mehrere Ports ab; sie wird nicht angefasst, sondern gemeldet |
Bei ufw wird dabei bewusst **nicht** nach Regelnummern gelöscht: die
verschieben sich beim ersten Löschen, der nächste Aufruf träfe die falsche
Regel. Stattdessen wird über die Regelangabe gelöscht
(`ufw delete allow 514/udp`), bei nftables über den Handle und bei iptables mit
derselben Regelangabe, mit der sie eingetragen wurde.
In der Oberfläche liegt das unter **Einstellungen → Firewall → Nicht mehr
benötigte Ports schließen**.
> **Docker und ufw:** Veröffentlichte Container-Ports umgehen ufw sonst über die
> `DOCKER-USER`-Kette. Hier nicht – beide Container laufen im Host-Netz, es
> gelten die Hostregeln unverändert.
@@ -2261,7 +2296,7 @@ Eine Dateiauswahl mit Verzeichnisnavigation ist eingebaut.
| `npm-reset` | Datenbank beiseitelegen, damit das Konto neu entsteht |
| `proxy status\|list\|certs\|add\|del` | Proxy-Hosts über die API anlegen und verwalten |
| `cert …` | selbstsigniertes Zertifikat erzeugen |
| `firewall [check\|open]` | prüfen, ob die benötigten Ports offen sind (firewalld, ufw, nftables, iptables) |
| `firewall [check\|open\|close]` | prüfen, öffnen und nicht mehr Benötigtes wieder schließen (firewalld, ufw, nftables, iptables) |
| `shell` | Root-Shell im Checkmk-Container |
| `omd …` | beliebiges `omd`-Kommando im Container |
+33 -1
View File
@@ -1988,6 +1988,38 @@ sense for 8000, 6557 and 514 (only the monitored hosts or the central site),
but not for port 80: Let's Encrypt probes the domain from the internet, and a
restriction makes issuance fail. The report points this out.
### Closing them again
`firewall open` only knows one direction. Turn the Event Console off again or
drop an entry from `FW_EXTRA_PORTS`, and the rule stays – the port is open with
nothing listening behind it. Hence the opposite direction:
```bash
./scripts/cmk-manage.sh firewall close # only print the commands
sudo ./scripts/cmk-manage.sh firewall close --apply
```
Only what is **open, belongs to this setup and is not currently needed** is
offered. That covers the ports from the table above plus everything
`firewall open --apply` opened itself – recorded in `firewall-opened.conf`, so
a deleted `FW_EXTRA_PORTS` entry is not forgotten.
Three safeguards are built in:
| | |
|---|---|
| **SSH stays open** | port 22, the port `sshd` actually listens on (from `sshd -T`), and the port of the running session (`SSH_CONNECTION`) |
| **Foreign rules stay** | if you have 3306 open for your database, you keep it – only what this setup knows about is closed |
| **Collective rules stay** | a rule like `80,443/tcp` covers several ports; it is reported instead of deleted |
With ufw the rules are deliberately **not** deleted by number: those shift on
the first deletion, and the next call would hit the wrong rule. Deletion goes
by rule specification instead (`ufw delete allow 514/udp`), with nftables by
handle, and with iptables using the same specification it was added with.
The GUI has this under **Einstellungen → Firewall → Nicht mehr benötigte Ports
schließen**.
> **Docker and ufw:** published container ports normally bypass ufw through the
> `DOCKER-USER` chain. Not here – both containers run in the host network, so
> the host rules apply unchanged.
@@ -2253,7 +2285,7 @@ A file chooser with directory navigation is built in.
| `npm-reset` | move the database aside so the account is recreated |
| `proxy status\|list\|certs\|add\|del` | create and manage proxy hosts through the API |
| `cert …` | create a self-signed certificate |
| `firewall [check\|open]` | check whether the required ports are open (firewalld, ufw, nftables, iptables) |
| `firewall [check\|open\|close]` | check, open, and close again what is no longer needed (firewalld, ufw, nftables, iptables) |
| `shell` | root shell in the Checkmk container |
| `omd …` | any `omd` command inside the container |
+350 -5
View File
@@ -52,9 +52,11 @@ KOMMANDOS - Stack
pull Images aktualisieren
status Status von Containern und Sites anzeigen
logs [-f] [DIENST] Logs anzeigen
firewall [check|open [--apply] [--source CIDR]]
firewall [check|open|close] [--apply] [--source CIDR]
Firewall pruefen: welche Ports der Stack braucht und
ob sie offen sind (firewalld, ufw, nftables, iptables)
ob sie offen sind (firewalld, ufw, nftables, iptables).
"close" schliesst wieder, was nicht mehr gebraucht wird
- SSH niemals, fremde Freigaben bleiben unberuehrt
selftest Skripte auf bekannte Fallstricke pruefen
tui-check Testzeilen fuer die Rahmendarstellung ausgeben
(hilft bei q/x/l/m statt Linien, etwa in PuTTY)
@@ -2007,6 +2009,7 @@ EOF
# dieser Datei erzeugt wird ("job auto on").
# =====================================================================
FW_STATE_FILE_NAME="firewall-opened.conf"
JOBS_FILE_NAME="backup-jobs.conf"
CRON_FILE="/etc/cron.d/checkmk-backup"
@@ -5402,7 +5405,8 @@ gui_settings_category() {
items+=("__npmrst__" ">> Datenbank zuruecksetzen (Konto neu anlegen lassen)") ;;
backup) items+=("__jobs__" ">> Backup-Jobs verwalten") ;;
firewall) items+=("__fwcheck__" ">> Firewall jetzt pruefen")
items+=("__fwapply__" ">> Firewall-Regeln uebernehmen (Ports oeffnen)") ;;
items+=("__fwapply__" ">> Firewall-Regeln uebernehmen (Ports oeffnen)")
items+=("__fwclose__" ">> Nicht mehr benoetigte Ports schliessen") ;;
esac
items+=("back" "zurueck")
local sel
@@ -5417,6 +5421,7 @@ gui_settings_category() {
__jobs__) gui_jobs_menu || true; continue ;;
__fwcheck__) gui_firewall || true; continue ;;
__fwapply__) gui_firewall_apply || true; continue ;;
__fwclose__) gui_firewall_close || true; continue ;;
__npm__) local f; f="$(mktemp)"
{ NO_COLOR=1 cmd_npm_enable; NO_COLOR=1 cmd_npm_port; } >"$f" 2>&1 || true
ui_text "NGINX Proxy Manager" "$f"; rm -f "$f"; continue ;;
@@ -6004,6 +6009,40 @@ Bitte als root erneut aufrufen."
return 0
}
# Nicht mehr benoetigte Ports wieder schliessen
gui_firewall_close() {
local tmp rc=0 hat=""
tmp="$(mktemp)"
cmd_firewall close >"$tmp" 2>&1 || rc=$?
if ( set +o pipefail; grep -q 'Zum Schliessen' "$tmp" ); then hat=1; fi
ui_text "Nicht mehr benoetigte Ports" "$tmp"
rm -f "$tmp"
[ -n "$hat" ] || return 0
ui_yesno "Ports schliessen" "Die angezeigten Ports jetzt schliessen?
SSH bleibt in jedem Fall offen - Port 22, der Port von sshd und der
Port dieser Sitzung. Freigaben fuer fremde Dienste werden nicht
angeruehrt." || return 0
local -a a=(firewall close --apply --yes)
if [ "$(id -u)" -eq 0 ]; then
ui_run "Ports schliessen" "$SELF" "${a[@]}" || true
elif command -v sudo >/dev/null 2>&1; then
gui_run_interactive sudo -- "$SELF" "${a[@]}"
else
ui_msg "Firewall" "Dafuer werden root-Rechte benoetigt.
Bitte als root erneut aufrufen."
return 0
fi
tmp="$(mktemp)"
cmd_firewall check >"$tmp" 2>&1 || true
ui_text "Firewall - Stand danach" "$tmp"
rm -f "$tmp"
return 0
}
gui_main() {
ui_require
while :; do
@@ -6369,9 +6408,301 @@ fw_open_cmds() { # backend port proto [quelle]
esac
}
# ---------------------------------------------------------------------
# Ports wieder zumachen
#
# "firewall open" kennt nur eine Richtung. Nimmt man einen Dienst
# wieder aus der Konfiguration - Event Console abgeschaltet, ein Port
# aus FW_EXTRA_PORTS gestrichen -, bleibt die Freigabe stehen.
#
# Zugemacht wird nur, was dieser Aufbau kennt: die Ports aus der Liste
# unten und das, was "firewall open --apply" selbst geoeffnet hat.
# Fremde Freigaben bleiben unangetastet - wer 3306 fuer seine Datenbank
# offen hat, soll sie behalten.
#
# SSH wird nie geschlossen. Weder Port 22 noch der Port, auf dem sshd
# tatsaechlich lauscht, noch der, ueber den diese Sitzung laeuft.
# ---------------------------------------------------------------------
# Alle Ports, die zu diesem Aufbau gehoeren koennten - unabhaengig davon,
# ob sie gerade gebraucht werden
fw_known_ports() {
printf '80/tcp|HTTP\n'
printf '443/tcp|HTTPS\n'
printf '%s/tcp|Adminoberflaeche des Proxy Managers\n' "${NPM_ADMIN_PORT:-81}"
printf '5000/tcp|Checkmk direkt\n'
printf '8000/tcp|Agent-Receiver\n'
printf '6557/tcp|Livestatus\n'
printf '6558/tcp|Event Console ueber TCP\n'
printf '6556/tcp|Checkmk-Agent dieses Hosts\n'
printf '514/udp|Event Console: Syslog\n'
printf '514/tcp|Event Console: Syslog ueber TCP\n'
printf '162/udp|Event Console: SNMP-Traps\n'
# Was wir selbst geoeffnet haben, gehoert auch dazu
local e
while IFS= read -r e; do
[ -n "$e" ] || continue
printf '%s|selbst geoeffnet\n' "$e"
done < <(fw_state_list)
}
fw_state_file() { printf '%s/%s\n' "$PROJECT_DIR" "$FW_STATE_FILE_NAME"; }
fw_state_list() {
local f; f="$(fw_state_file)"
[ -f "$f" ] || return 0
sed 's/#.*//; s/[[:space:]]//g' "$f" | sed '/^$/d' | sort -u
}
fw_state_add() { # port/proto
local f; f="$(fw_state_file)"
if [ ! -f "$f" ]; then
cat >"$f" <<'EOF'
# Von "cmk-manage.sh firewall open --apply" geoeffnete Ports.
# Dient "firewall close" als Gedaechtnis - hier stehen nur Eintraege,
# die dieses Werkzeug selbst gesetzt hat. Von Hand geaendert werden
# muss hier nichts.
EOF
fi
( set +o pipefail; grep -qxF "$1" "$f" ) || printf '%s\n' "$1" >>"$f"
}
fw_state_del() { # port/proto
local f tmp; f="$(fw_state_file)"
[ -f "$f" ] || return 0
tmp="$f.tmp"
# Bleibt nichts uebrig, liefert grep 1 - das darf weder die Datei
# stehen lassen noch unter "set -e" den Ablauf beenden.
grep -vxF "$1" "$f" > "$tmp" 2>/dev/null || true
mv "$tmp" "$f" 2>/dev/null || rm -f "$tmp"
return 0
}
# Ports, die unter keinen Umstaenden geschlossen werden
fw_protected_ports() {
printf '22/tcp\n'
# Wo lauscht sshd wirklich?
if command -v sshd >/dev/null 2>&1; then
sshd -T 2>/dev/null | sed -n 's/^port[[:space:]]\+\([0-9]\+\).*/\1\/tcp/p'
fi
sed -n 's/^[[:space:]]*[Pp]ort[[:space:]]\+\([0-9]\+\).*/\1\/tcp/p' \
/etc/ssh/sshd_config 2>/dev/null
# Und der Port, ueber den diese Sitzung gerade laeuft
if [ -n "${SSH_CONNECTION:-}" ]; then
printf '%s/tcp\n' "$(printf '%s' "$SSH_CONNECTION" | awk '{print $4}')"
fi
}
# Kommandos zum Schliessen. Anders als beim Oeffnen reicht eine Vorlage
# nicht: die Regel muss so getroffen werden, wie sie dasteht.
fw_close_cmds() { # backend port proto
local be="$1" port="$2" proto="$3"
case "$be" in
firewalld)
local zone svc rule
while IFS= read -r zone; do
[ -n "$zone" ] || continue
local plist
plist="$(firewall-cmd --zone="$zone" --list-ports 2>/dev/null | tr ' ' '\n')"
if ( set +o pipefail; printf '%s\n' "$plist" | grep -qxF "$port/$proto" ); then
printf 'firewall-cmd --permanent --zone=%s --remove-port=%s/%s\n' "$zone" "$port" "$proto"
fi
while IFS= read -r svc; do
[ -n "$svc" ] || continue
if ( set +o pipefail; fw_service_port "$svc" | grep -qxF "$port/$proto" ); then
printf 'firewall-cmd --permanent --zone=%s --remove-service=%s\n' "$zone" "$svc"
fi
done < <(firewall-cmd --zone="$zone" --list-services 2>/dev/null | tr ' ' '\n')
while IFS= read -r rule; do
[ -n "$rule" ] || continue
case "$rule" in
*"port=\"$port\""*"protocol=\"$proto\""*)
printf "firewall-cmd --permanent --zone=%s --remove-rich-rule='%s'\n" "$zone" "$rule" ;;
esac
done < <(firewall-cmd --zone="$zone" --list-rich-rules 2>/dev/null)
done < <(fw_zones) ;;
ufw)
# NICHT nach Nummern loeschen: die verschieben sich beim
# ersten Loeschen, und der naechste Aufruf traefe die falsche
# Regel. Ueber die Regelangabe ist es von der Reihenfolge
# unabhaengig. Deckt eine Regel mehrere Ports ab, bleibt sie
# stehen - sonst faellt mehr weg als gewollt.
ufw status numbered 2>/dev/null \
| awk -v p="$port" -v pr="$proto" '
/^\[/ {
line = $0
sub(/^\[[ \t]*[0-9]+\][ \t]*/, "", line)
if (line ~ /\(v6\)/) next # ufw loescht v4 und v6 zusammen
n = split(line, f, /[ \t]+/)
spec = f[1]; act = ""; from = ""
for (i = 2; i <= n; i++) {
if (f[i] == "ALLOW" || f[i] == "DENY" || f[i] == "LIMIT" || f[i] == "REJECT") {
act = f[i]; j = i + 1
if (f[j] == "IN" || f[j] == "OUT" || f[j] == "FWD") j++
for (; j <= n; j++) from = from (from == "" ? "" : " ") f[j]
break
}
}
if (act != "ALLOW") next
split(spec, a, "/")
plist = a[1]; sp = (length(a) > 1 ? a[2] : "")
if (sp != "" && sp != pr) next
m = split(plist, b, ",")
for (i = 1; i <= m; i++) if (b[i] == p) {
if (m > 1) {
printf "# Regel \"%s\" deckt mehrere Ports ab - bitte von Hand: ufw status numbered\n", spec
} else if (from == "Anywhere" || from == "") {
printf "ufw delete allow %s\n", spec
} else {
printf "ufw delete allow from %s to any port %s", from, p
if (sp != "") printf " proto %s", sp
printf "\n"
}
next
}
}' ;;
iptables)
# Die Regel so loeschen, wie sie eingetragen ist. Sammelregeln
# (--dports 80,443) bleiben stehen, sonst faellt mehr weg als
# gewollt.
iptables -S 2>/dev/null | grep -E ' -j (ACCEPT|accept)$' \
| while IFS= read -r line; do
case "$line" in "-A "*) : ;; *) continue ;; esac
case "$line" in *" -p $proto "*) : ;; *) continue ;; esac
local plist=""
plist="$(printf '%s' "$line" | sed -n 's/.*--dports\{0,1\} \([0-9,:]*\).*/\1/p')"
[ -n "$plist" ] || continue
case ",$plist," in *",$port,"*) : ;; *) continue ;; esac
case "$plist" in
*,*) printf '# Regel deckt mehrere Ports ab (%s) - bitte von Hand: iptables -S\n' "$plist" ;;
*) printf 'iptables -D %s\n' "${line#-A }" ;;
esac
done ;;
nftables)
# Geloescht wird ueber den Handle. Steht der Port in einer
# Menge mit anderen, bleibt die Regel stehen.
nft -a list ruleset 2>/dev/null \
| awk -v p="$port" -v pr="$proto" '
/^table / { fam = $2; tbl = $3 }
/^[[:space:]]*chain / { ch = $2 }
$0 ~ (pr " dport") && $0 ~ /handle [0-9]+$/ {
line = $0
h = line; sub(/.*handle /, "", h)
if (match(line, /dport[ \t]*\{[^}]*\}/)) {
set = substr(line, RSTART, RLENGTH)
sub(/dport[ \t]*\{/, "", set); sub(/\}/, "", set)
gsub(/[ \t]/, "", set)
n = split(set, a, ",")
for (i = 1; i <= n; i++) if (a[i] == p) {
if (n > 1)
printf "# Regel %s deckt mehrere Ports ab (%s) - bitte von Hand: nft -a list ruleset\n", h, set
else
printf "nft delete rule %s %s %s handle %s\n", fam, tbl, ch, h
}
} else if (match(line, ("dport[ \t]+" p "([^0-9]|$)"))) {
printf "nft delete rule %s %s %s handle %s\n", fam, tbl, ch, h
}
}' ;;
esac
}
# Welche Ports sind offen, gehoeren zu diesem Aufbau, werden aber nicht
# mehr gebraucht?
fw_close_report() { # backend apply
local be="$1" apply="${2:-}"
local spec need port proto desc
local -a todo=()
# Was gebraucht wird, darf nicht weg
local noetig=""
while IFS='|' read -r spec desc need; do
[ -n "$spec" ] || continue
case "$need" in ja|admin) noetig="$noetig$spec"$'\n' ;; esac
done < <(fw_required_ports)
local geschuetzt; geschuetzt="$(fw_protected_ports | sed '/^$/d' | sort -u)"
printf '\n%sNicht mehr benoetigt%s\n' "$C_BLD" "$C_RST"
printf ' %-10s %-44s %s\n' "PORT" "GEHOERT ZU" "ZUSTAND"
local seen=""
while IFS='|' read -r spec desc; do
[ -n "$spec" ] || continue
case "$seen" in *"|$spec|"*) continue ;; esac
seen="$seen|$spec|"
port="${spec%/*}"; proto="${spec##*/}"
fw_port_open "$port" "$proto" || continue
if ( set +o pipefail; printf '%s' "$noetig" | grep -qxF "$spec" ); then continue; fi
if ( set +o pipefail; printf '%s' "$geschuetzt" | grep -qxF "$spec" ); then
printf ' %-10s %-44s %b\n' "$spec" "$desc" "${C_GRN}bleibt offen (SSH)${C_RST}"
continue
fi
todo+=("$spec")
printf ' %-10s %-44s %b\n' "$spec" "$desc" "${C_YEL}kann zu${C_RST}"
done < <(fw_known_ports)
if [ "${#todo[@]}" -eq 0 ]; then
echo
ok "Es ist nichts offen, was nicht gebraucht wird."
printf ' Fremde Freigaben - etwa fuer andere Dienste auf diesem Rechner -
werden dabei nicht angeruehrt.\n\n'
return 0
fi
printf '\n%sZum Schliessen%s\n' "$C_BLD" "$C_RST"
local t c n=0
for t in "${todo[@]}"; do
while IFS= read -r c; do
[ -n "$c" ] || continue
printf ' %s\n' "$c"; n=$((n+1))
done < <(fw_close_cmds "$be" "${t%/*}" "${t##*/}")
done
if [ "$n" -eq 0 ]; then
echo
warn "Die Regeln liessen sich nicht zuordnen - bitte von Hand pruefen."
echo; return 0
fi
case "$be" in
firewalld) printf ' firewall-cmd --reload\n' ;;
iptables) printf ' # dauerhaft machen: iptables-save bzw. iptables-persistent\n' ;;
nftables) printf ' # dauerhaft machen: /etc/nftables.conf nachziehen\n' ;;
esac
if [ -z "$apply" ]; then
printf '\n Ausfuehren mit: %s firewall close --apply\n\n' "$SELF"
return 0
fi
echo
if [ "$(id -u)" -ne 0 ]; then
die "Dafuer werden root-Rechte benoetigt - bitte mit sudo erneut aufrufen."
fi
confirm "Diese Ports jetzt schliessen?" || die "Abgebrochen."
for t in "${todo[@]}"; do
local fehler=""
while IFS= read -r c; do
[ -n "$c" ] || continue
case "$c" in
\#*) warn "${c#\# }"; fehler=1; continue ;;
esac
log "$c"
eval "$c" || { warn "Fehlgeschlagen: $c"; fehler=1; }
done < <(fw_close_cmds "$be" "${t%/*}" "${t##*/}")
if [ -z "$fehler" ]; then fw_state_del "$t"; fi
done
if [ "$be" = firewalld ]; then
firewall-cmd --reload >/dev/null 2>&1 && ok "firewalld neu geladen." \
|| warn "Neuladen fehlgeschlagen."
fi
ok "Ports geschlossen."
echo
return 0
}
cmd_firewall() {
local sub="${1:-check}"; [ $# -gt 0 ] && shift || true
case "$sub" in check|open) : ;; *) die "Unbekannt: firewall $sub (check|open)" ;; esac
case "$sub" in check|open|close) : ;; *) die "Unbekannt: firewall $sub (check|open|close)" ;; esac
local apply="" src=""
while [ $# -gt 0 ]; do
case "$1" in
@@ -6410,6 +6741,15 @@ cmd_firewall() {
printf ' Offene Ports: %s\n' "$(printf '%s' "$_FW_OPEN" | tr '\n' ' ' | sed 's/ $//')"
fi
if [ "$sub" = close ]; then
if [ "$be" = keine ]; then
echo; warn "Ohne erkannte Firewall gibt es nichts zu schliessen."; echo
return 0
fi
fw_close_report "$be" "$apply"
return $?
fi
printf '\n%sWas dieser Stack braucht%s\n' "$C_BLD" "$C_RST"
printf ' %-10s %-48s %-7s %s\n' "PORT" "ZWECK" "NOETIG" "ZUSTAND"
@@ -6486,7 +6826,12 @@ cmd_firewall() {
for t in "${todo[@]}"; do
c="$(fw_open_cmds "$be" "${t%/*}" "${t##*/}" "$src")"
log "$c"
eval "$c" || warn "Fehlgeschlagen: $c"
if eval "$c"; then
# Merken, damit "firewall close" spaeter weiss, was von uns war
fw_state_add "$t"
else
warn "Fehlgeschlagen: $c"
fi
done
if [ "$be" = firewalld ]; then
firewall-cmd --reload >/dev/null 2>&1 && ok "firewalld neu geladen." \