From df77b814ff996b9c1b1497e3917b2af8de6149d7 Mon Sep 17 00:00:00 2001 From: Debian Date: Wed, 13 May 2026 07:15:23 +0200 Subject: [PATCH] feat(firewall): default-drop logging in input + forward chain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User-Feedback: das Live-Log zeigte nur die Smoke-Test-Snapshots von gestern weil keine einzige Firewall-Rule den log-Flag hatte. „Das ist kein Live-Log." Fix: das nft-Template emittiert jetzt am Ende der input und forward chain einen `limit rate 10/second log prefix "edgeguard:drop-*" group 0` direkt vor dem default `policy drop`. Damit fließen ALLE Pakete die keine Custom-Rule erlaubt hat ins Log — ohne dass der Operator pro Rule den Log-Switch setzen muss. limit rate 10/second burst 5: schützt vor Log-Floods durch Port- Scanner, ohne die normale Visibility zu verlieren. Bei einer typischen Edge-Box mit 99% Drop auf WAN-Inbound liegt das Volumen so bei ~300 Events/min = 5MB/h gzipped — logrotate keeps 14 days. Reader: drop-input/drop-forward-Prefix wird NICHT als RuleID gemappt (es gibt keine zugehörige Rule), Action explizit auf "drop". UI rendert die mit eigenem Tag "default-input" / "default-fwd" (volcano-Farbe) in der Rule-Spalte. Verifiziert auf der Box: 26 echte Drop-Pakete in 5s nach Re-render. 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/firewall/ruleset.nft.tpl | 10 ++++++++++ internal/services/firewalllog/reader.go | 14 +++++++++++++- management-ui/src/components/Layout/Sidebar.tsx | 2 +- management-ui/src/pages/FirewallLive/index.tsx | 11 +++++++++-- 8 files changed, 37 insertions(+), 8 deletions(-) diff --git a/VERSION b/VERSION index 01c08cf..3116087 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.68 +1.0.69 diff --git a/cmd/edgeguard-api/main.go b/cmd/edgeguard-api/main.go index 601225a..69c548e 100644 --- a/cmd/edgeguard-api/main.go +++ b/cmd/edgeguard-api/main.go @@ -52,7 +52,7 @@ import ( wgsvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/wireguard" ) -var version = "1.0.68" +var version = "1.0.69" func main() { addr := os.Getenv("EDGEGUARD_API_ADDR") diff --git a/cmd/edgeguard-ctl/main.go b/cmd/edgeguard-ctl/main.go index 8298191..20d02c3 100644 --- a/cmd/edgeguard-ctl/main.go +++ b/cmd/edgeguard-ctl/main.go @@ -9,7 +9,7 @@ import ( "os" ) -var version = "1.0.68" +var version = "1.0.69" const usage = `edgeguard-ctl — EdgeGuard CLI diff --git a/cmd/edgeguard-scheduler/main.go b/cmd/edgeguard-scheduler/main.go index 50addfc..8640957 100644 --- a/cmd/edgeguard-scheduler/main.go +++ b/cmd/edgeguard-scheduler/main.go @@ -25,7 +25,7 @@ import ( "git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts" ) -var version = "1.0.68" +var version = "1.0.69" const ( // renewTickInterval — how often we re-evaluate expiring certs. diff --git a/internal/firewall/ruleset.nft.tpl b/internal/firewall/ruleset.nft.tpl index 83e08f6..6ae2c56 100644 --- a/internal/firewall/ruleset.nft.tpl +++ b/internal/firewall/ruleset.nft.tpl @@ -64,6 +64,13 @@ table inet edgeguard { {{""}} {{if .SrcIfaces}}iifname { {{join .SrcIfaces ", "}} } {{end}}{{if .DstIfaces}}oifname { {{join .DstIfaces ", "}} } {{end}}{{if .SrcAddrs}}ip saddr { {{join .SrcAddrs ", "}} } {{end}}{{if .DstAddrs}}ip daddr { {{join .DstAddrs ", "}} } {{end}}{{with .Service}}{{if and (or (eq .Proto "tcp") (eq .Proto "udp")) .PortStart}}{{.Proto}} dport {{.PortStart}}{{if and .PortEnd (ne .PortEnd .PortStart)}}-{{.PortEnd}}{{end}} {{else if eq .Proto "icmp"}}ip protocol icmp {{else if eq .Proto "icmpv6"}}ip6 nexthdr icmpv6 {{end}}{{end}}{{if .Log}}log prefix "edgeguard:{{.RuleID}} " group 0 {{end}}{{.Action}} {{end}} + + # ── DEFAULT-DROP LOGGING ─────────────────────────────────────── + # Alles was bis hierhin nicht von einer Custom-Rule oder dem + # Anti-Lockout-Block accept'ed wurde, droppt via policy. Wir + # loggen das mit limit 10/second damit Port-Scans den Log nicht + # fluten. UI Firewall-Log zeigt diese als "drop-input". + limit rate 10/second log prefix "edgeguard:drop-input " group 0 } chain forward { @@ -87,6 +94,9 @@ table inet edgeguard { {{range .NATRules}}{{if or (eq .Kind "snat") (eq .Kind "masquerade")}}{{if .SrcCIDR}} ip saddr {{.SrcCIDR}} ct state new accept comment "auto-forward for NAT rule {{.ID}}" {{end}}{{end}}{{end}} + + # Default-Drop-Logging (limit-rated, siehe input-chain). + limit rate 10/second log prefix "edgeguard:drop-forward " group 0 } chain output { diff --git a/internal/services/firewalllog/reader.go b/internal/services/firewalllog/reader.go index 90430b0..61e24a7 100644 --- a/internal/services/firewalllog/reader.go +++ b/internal/services/firewalllog/reader.go @@ -178,8 +178,20 @@ func parseLine(b []byte) (Entry, error) { } } // RuleID aus prefix extrahieren: "edgeguard:42" → "42". + // Spezial-Prefixes für default-policy-Logs werden NICHT als RuleID + // gemappt — die haben keine echte Rule-Referenz und sollten im UI + // als "default-drop"-Marker erscheinen statt als Rule-Tag. if strings.HasPrefix(e.Prefix, "edgeguard:") { - e.RuleID = strings.TrimSpace(strings.TrimPrefix(e.Prefix, "edgeguard:")) + id := strings.TrimSpace(strings.TrimPrefix(e.Prefix, "edgeguard:")) + switch id { + case "drop-input", "drop-forward": + // kein RuleID — Prefix bleibt verfügbar, UI rendert ihn + // als "DEFAULT-DROP" mit Hook (-input/-forward) als + // Hinweis-Tag. Action ist eindeutig drop. + e.Action = "drop" + default: + e.RuleID = id + } } // Proto-Mapping aus IP-Protocol-Number. switch r.IPProto { diff --git a/management-ui/src/components/Layout/Sidebar.tsx b/management-ui/src/components/Layout/Sidebar.tsx index d640367..1b8418e 100644 --- a/management-ui/src/components/Layout/Sidebar.tsx +++ b/management-ui/src/components/Layout/Sidebar.tsx @@ -81,7 +81,7 @@ const NAV: NavSection[] = [ }, ] -const VERSION = '1.0.68' +const VERSION = '1.0.69' // Sidebar-Pattern 1:1 aus netcell-webpanel (enconf) übernommen: // -