package firewall import ( "fmt" "os" "os/exec" "path/filepath" "gitea.perlbach24.de/scripte/wireguard-ui-multi/internal/server" ) // HooksDir holds optional user-defined shell scripts run around lifecycle events. var HooksDir = "/etc/wireguard-manager/hooks" // HookEvent names the lifecycle points a hook script may exist for. type HookEvent string const ( HookServerStart HookEvent = "server-start" HookServerStop HookEvent = "server-stop" HookPeerAdd HookEvent = "peer-add" HookPeerRemove HookEvent = "peer-remove" ) // RunHook executes /etc/wireguard-manager/hooks/ if present and executable, // passing iface (and optionally peer pubkey) as arguments. Missing hook is not an error. func RunHook(event HookEvent, args ...string) error { path := filepath.Join(HooksDir, string(event)) if _, err := os.Stat(path); err != nil { return nil // hook not installed, skip silently } cmd := exec.Command(path, args...) if out, err := cmd.CombinedOutput(); err != nil { return fmt.Errorf("hook %s: %w: %s", event, err, out) } return nil } // NFTRuleset renders a suggested nftables ruleset snippet for a server, allowing // its UDP listen port in and forwarding traffic between the tunnel and lanIface. func NFTRuleset(srv *server.Server, lanIface string) string { return fmt.Sprintf(`table inet wireguard_%s { chain input { type filter hook input priority 0; policy accept; udp dport %d accept } chain forward { type filter hook forward priority 0; policy accept; iifname "%s" oifname "%s" accept iifname "%s" oifname "%s" accept } } `, srv.InterfaceName, srv.ListenPort, srv.InterfaceName, lanIface, lanIface, srv.InterfaceName) } // ApplyRuleset writes the ruleset to a temp file and loads it with `nft -f`. func ApplyRuleset(srv *server.Server, lanIface string) error { tmp, err := os.CreateTemp("", "wgm-nft-*.conf") if err != nil { return err } defer os.Remove(tmp.Name()) if _, err := tmp.WriteString(NFTRuleset(srv, lanIface)); err != nil { tmp.Close() return err } tmp.Close() cmd := exec.Command("nft", "-f", tmp.Name()) if out, err := cmd.CombinedOutput(); err != nil { return fmt.Errorf("nft -f: %w: %s", err, out) } return nil }