Add central host-wide firewall allow/block lists

New model.IPListEntry + jsondb CRUD, independent of any single WireGuard
server. firewall.GenerateGlobalRuleset builds an nftables table
(wireguard_ui_global) with allow/block sets evaluated at priority -10 -
before every per-server table - so it applies to all traffic on the host,
not just WireGuard. Allow entries always win over block entries.
firewall.ApplyGlobal loads it live via `nft -f`, scoped to that one table.

New "Global Firewall Lists" page (nav entry under Settings): add/delete
entries, ruleset preview, "Apply now (live)" with an explicit confirm()
warning since this affects the whole host's firewall, not just one server.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
sysops
2026-07-12 17:45:53 +02:00
co-authored by Claude Sonnet 5
parent bdcf1ec60c
commit eb1913d400
10 changed files with 438 additions and 9 deletions
+30
View File
@@ -736,3 +736,33 @@ func (o *JsonDB) DeleteFirewallRule(serverID, ruleID string) error {
}
return o.conn.Delete("firewall_rules", ruleID)
}
// GetIPListEntries func to query every host-wide allow/block list entry
func (o *JsonDB) GetIPListEntries() ([]model.IPListEntry, error) {
entries := make([]model.IPListEntry, 0)
records, err := o.conn.ReadAll("ip_list_entries")
if err != nil {
if err == scribble.ErrMissingCollection {
return entries, nil
}
return nil, err
}
for _, rec := range records {
var entry model.IPListEntry
if err := json.Unmarshal(rec, &entry); err != nil {
return nil, fmt.Errorf("cannot decode ip list entry json structure: %v", err)
}
entries = append(entries, entry)
}
return entries, nil
}
// CreateIPListEntry func to add a new host-wide allow/block list entry
func (o *JsonDB) CreateIPListEntry(entry model.IPListEntry) error {
return o.conn.Write("ip_list_entries", entry.ID, entry)
}
// DeleteIPListEntry func to remove a host-wide allow/block list entry
func (o *JsonDB) DeleteIPListEntry(id string) error {
return o.conn.Delete("ip_list_entries", id)
}
+3
View File
@@ -38,4 +38,7 @@ type IStore interface {
CreateFirewallRule(rule model.FirewallRule) error
UpdateFirewallRule(rule model.FirewallRule) error
DeleteFirewallRule(serverID, ruleID string) error
GetIPListEntries() ([]model.IPListEntry, error)
CreateIPListEntry(entry model.IPListEntry) error
DeleteIPListEntry(id string) error
}