From 94643224503fe0d38afceef79ddb42e0842de9bb Mon Sep 17 00:00:00 2001 From: Debian Date: Mon, 11 May 2026 07:51:55 +0200 Subject: [PATCH] fix(dashboard): nftables-Status aus Kernel statt Systemd-Unit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vorher: Service-Health-Grid hat 'nftables.service' per systemctl abgefragt. Distro-Unit ist disabled (wir laden via 'nft -f' aus dem Renderer) → Dashboard zeigte FW als 'inactive', obwohl Pakete sehr wohl gefiltert werden. Fix: Special-case in /system/services für unit='nftables'. Status = existiert 'table inet edgeguard' im Kernel-Ruleset (sudo nft list tables). 'kernel-loaded' wenn ja, 'no-table' wenn nein. Plus: sudoers im postinst erweitert um 'nft list tables' + 'nft list table inet edgeguard'. Version 1.0.44. Co-Authored-By: Claude Opus 4.7 (1M context) --- VERSION | 2 +- cmd/edgeguard-api/main.go | 2 +- cmd/edgeguard-ctl/main.go | 2 +- cmd/edgeguard-scheduler/main.go | 2 +- internal/handlers/system.go | 36 +++++++++++++++++-- management-ui/package.json | 2 +- .../src/components/Layout/Sidebar.tsx | 2 +- .../debian/edgeguard-api/DEBIAN/postinst | 2 ++ 8 files changed, 42 insertions(+), 8 deletions(-) diff --git a/VERSION b/VERSION index f683e66..6ae122f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.43 +1.0.44 diff --git a/cmd/edgeguard-api/main.go b/cmd/edgeguard-api/main.go index 767a555..688fb04 100644 --- a/cmd/edgeguard-api/main.go +++ b/cmd/edgeguard-api/main.go @@ -45,7 +45,7 @@ import ( wgsvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/wireguard" ) -var version = "1.0.43" +var version = "1.0.44" func main() { addr := os.Getenv("EDGEGUARD_API_ADDR") diff --git a/cmd/edgeguard-ctl/main.go b/cmd/edgeguard-ctl/main.go index ddaff29..74be907 100644 --- a/cmd/edgeguard-ctl/main.go +++ b/cmd/edgeguard-ctl/main.go @@ -9,7 +9,7 @@ import ( "os" ) -var version = "1.0.43" +var version = "1.0.44" const usage = `edgeguard-ctl — EdgeGuard CLI diff --git a/cmd/edgeguard-scheduler/main.go b/cmd/edgeguard-scheduler/main.go index cbd089d..5e6e4db 100644 --- a/cmd/edgeguard-scheduler/main.go +++ b/cmd/edgeguard-scheduler/main.go @@ -21,7 +21,7 @@ import ( "git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts" ) -var version = "1.0.43" +var version = "1.0.44" const ( // renewTickInterval — how often we re-evaluate expiring certs. diff --git a/internal/handlers/system.go b/internal/handlers/system.go index 7708ecc..e60fe42 100644 --- a/internal/handlers/system.go +++ b/internal/handlers/system.go @@ -2,6 +2,7 @@ package handlers import ( "bufio" + stdcontext "context" "log/slog" "net" "net/http" @@ -67,8 +68,21 @@ func (h *SystemHandler) Services(c *gin.Context) { out := make([]serviceStatus, 0, len(servicesToCheck)) for _, s := range servicesToCheck { st := serviceStatus{Label: s.Label, Unit: s.Unit} - // systemctl show -p SubState,ActiveEnterTimestamp gives us - // state + since in one shot, faster than two calls. + if s.Unit == "nftables" { + // Distro-Unit nftables.service ist disabled — wir laden + // die Rules direkt via 'nft -f' aus dem Renderer. Status + // = ist unsere 'inet edgeguard'-Tabelle im Kernel? + loaded, when := nftablesKernelState(c.Request.Context()) + st.Active = loaded + if loaded { + st.State = "kernel-loaded" + } else { + st.State = "no-table" + } + st.Since = when + out = append(out, st) + continue + } raw, err := exec.CommandContext(c.Request.Context(), "systemctl", "show", "-p", "ActiveState,ActiveEnterTimestamp", s.Unit).Output() @@ -90,6 +104,24 @@ func (h *SystemHandler) Services(c *gin.Context) { response.OK(c, gin.H{"services": out}) } +// nftablesKernelState reports whether our 'inet edgeguard' table is +// present in the kernel ruleset. Errors swallow to false. Returns +// the mtime of the source file as 'since' when loaded. +func nftablesKernelState(ctx stdcontext.Context) (bool, string) { + out, err := exec.CommandContext(ctx, "sudo", "-n", "/usr/sbin/nft", "list", "tables").Output() + if err != nil { + return false, "" + } + if !strings.Contains(string(out), "inet edgeguard") { + return false, "" + } + when := "" + if fi, err := os.Stat("/etc/edgeguard/nftables.d/ruleset.nft"); err == nil { + when = fi.ModTime().UTC().Format(time.RFC3339) + } + return true, when +} + type resources struct { LoadAvg1 float64 `json:"load_avg_1"` LoadAvg5 float64 `json:"load_avg_5"` diff --git a/management-ui/package.json b/management-ui/package.json index addf953..2932f37 100644 --- a/management-ui/package.json +++ b/management-ui/package.json @@ -1,7 +1,7 @@ { "name": "edgeguard-management-ui", "private": true, - "version": "1.0.43", + "version": "1.0.44", "type": "module", "scripts": { "dev": "vite", diff --git a/management-ui/src/components/Layout/Sidebar.tsx b/management-ui/src/components/Layout/Sidebar.tsx index 54082d1..cee0a31 100644 --- a/management-ui/src/components/Layout/Sidebar.tsx +++ b/management-ui/src/components/Layout/Sidebar.tsx @@ -75,7 +75,7 @@ const NAV: NavSection[] = [ }, ] -const VERSION = '1.0.43' +const VERSION = '1.0.44' export default function Sidebar({ isOpen, onClose }: SidebarProps) { const { t } = useTranslation() diff --git a/packaging/debian/edgeguard-api/DEBIAN/postinst b/packaging/debian/edgeguard-api/DEBIAN/postinst index d72b605..fe7a1d7 100755 --- a/packaging/debian/edgeguard-api/DEBIAN/postinst +++ b/packaging/debian/edgeguard-api/DEBIAN/postinst @@ -53,6 +53,8 @@ case "$1" in edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl reload haproxy.service edgeguard ALL=(root) NOPASSWD: /bin/systemctl reload haproxy.service edgeguard ALL=(root) NOPASSWD: /usr/sbin/nft -f /etc/edgeguard/nftables.d/ruleset.nft +edgeguard ALL=(root) NOPASSWD: /usr/sbin/nft list tables +edgeguard ALL=(root) NOPASSWD: /usr/sbin/nft list table inet edgeguard edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl start wg-quick@*.service edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl restart wg-quick@*.service edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl stop wg-quick@*.service