New firewall.DisableGlobal() removes the wireguard_ui_global nftables
table without touching stored IP list entries, and firewall.IsGlobalEnabled()
reports whether it's currently loaded. New GET /firewall-lists/status and
POST /firewall-lists/disable endpoints (admin-only), plus a status badge
and "Toggle enable/disable" button on the Global Firewall Lists page -
one click to turn the whole thing off without losing the list contents,
and back on again (re-applies the current ruleset).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
auto-merge is a standalone set statement, not an nft "flags" value -
"flags interval, auto-merge;" is a syntax error; fixed to "flags
interval;" followed by "auto-merge" on its own line. Needed because large
public blocklists (FireHOL, Spamhaus) contain overlapping CIDRs that
nftables otherwise refuses as "conflicting intervals".
Also add a hard guard: reject any "block" entry that overlaps a private/
reserved/bogon range (RFC1918, CGNAT, loopback, link-local, etc.) in both
the single-entry and bulk-import paths. Public feeds like FireHOL level1
routinely include ranges like 10.0.0.0/8 and 172.16.0.0/12, meant for
WAN-only edge firewalls - applied host-wide here (where WireGuard/LAN
subnets legitimately live in that same private space), those entries
would silently block a server's own internal/VPN traffic instead of
actual bad actors.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
New model.FirewallRule + jsondb CRUD (GetFirewallRules/CreateFirewallRule/
UpdateFirewallRule/DeleteFirewallRule), scoped per server. firewall package
now generates a full ruleset (baseline + enabled custom rules) and can
apply it live via `nft -f` (firewall.Apply), scoped to a per-server
nftables table (wireguard_ui_<serverID>) so applying one server never
touches another server's rules or any pre-existing firewall state.
New endpoints: GET/POST /servers/:id/firewall/rules, POST .../rules/:ruleId,
POST .../rules/:ruleId/delete, POST .../apply (live, admin-only). UI in the
All Servers page: rule table with add/delete, ruleset preview, and an
"Apply now (live)" button with an explicit confirm() warning before it
touches the running firewall.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New firewall package generates an nftables snippet (INPUT accept for the
listen port, FORWARD rules for the WireGuard interface, optional LAN
forwarding via a new ServerSetting.LanInterface field). Text only -
nothing is applied to the live firewall. Exposed as GET
/servers/:id/firewall-preview and a "Firewall Preview" button in the
All Servers page.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>