Files
wireguard-ui-multi/firewall/nftables.go
T
sysopsandClaude Sonnet 5 28eb08df41 Add nftables firewall ruleset preview per server (review-only)
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>
2026-07-12 16:52:20 +02:00

57 lines
2.4 KiB
Go

// Package firewall generates an nftables ruleset preview for a WireGuard
// server. It never touches the live firewall - the output is text only,
// meant to be reviewed and applied manually (nft -f <file>) or copied into
// an existing ruleset.
package firewall
import (
"fmt"
"strings"
"github.com/ngoduykhanh/wireguard-ui/model"
)
// GeneratePreview renders an nftables ruleset snippet for the given server.
// If settings.LanInterface is empty, only WireGuard-interface-local traffic
// rules are emitted; forwarding to a LAN interface is added when set.
func GeneratePreview(server model.Server, settings model.ServerSetting) string {
ifaceName := "wgX"
listenPort := 0
if server.Interface != nil {
if server.Interface.Name != "" {
ifaceName = server.Interface.Name
}
listenPort = server.Interface.ListenPort
}
var b strings.Builder
fmt.Fprintf(&b, "# nftables ruleset preview for server %q (%s)\n", server.Name, server.ID)
fmt.Fprintf(&b, "# Generated by wireguard-ui-multi - review before applying, e.g.:\n")
fmt.Fprintf(&b, "# nft -f this-file.nft\n")
fmt.Fprintf(&b, "# Not applied automatically.\n\n")
fmt.Fprintf(&b, "table inet wireguard_ui_%s {\n", server.ID)
fmt.Fprintf(&b, " chain input {\n")
fmt.Fprintf(&b, " type filter hook input priority 0; policy accept;\n")
fmt.Fprintf(&b, " udp dport %d accept comment \"wg-ui-multi: %s\"\n", listenPort, server.ID)
fmt.Fprintf(&b, " }\n\n")
fmt.Fprintf(&b, " chain forward {\n")
fmt.Fprintf(&b, " type filter hook forward priority 0; policy accept;\n")
fmt.Fprintf(&b, " iifname \"%s\" accept comment \"wg-ui-multi: %s inbound\"\n", ifaceName, server.ID)
fmt.Fprintf(&b, " oifname \"%s\" accept comment \"wg-ui-multi: %s outbound\"\n", ifaceName, server.ID)
if settings.LanInterface != "" {
fmt.Fprintf(&b, " iifname \"%s\" oifname \"%s\" accept comment \"wg-ui-multi: %s -> lan\"\n", ifaceName, settings.LanInterface, server.ID)
fmt.Fprintf(&b, " iifname \"%s\" oifname \"%s\" accept comment \"wg-ui-multi: lan -> %s\"\n", settings.LanInterface, ifaceName, server.ID)
}
fmt.Fprintf(&b, " }\n")
fmt.Fprintf(&b, "}\n")
if settings.LanInterface == "" {
fmt.Fprintf(&b, "\n# No LAN interface configured for this server - peers can only reach\n")
fmt.Fprintf(&b, "# each other, not your LAN. Set one in Server Settings to add forwarding.\n")
}
return b.String()
}