Firewall added & some fixes

This commit is contained in:
MoonDev
2026-04-13 12:40:49 +03:00
parent 7eaa9750b0
commit 8c35022483
22 changed files with 1659 additions and 134 deletions

View File

@@ -6,19 +6,13 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"
)
const tableName = "alpine-router-nat"
// Config holds NAT masquerade settings per interface.
type Config struct {
// Interfaces is the list of LAN interface names for which masquerade is enabled.
// Traffic arriving on these interfaces will be NATted to the outgoing WAN interface.
Interfaces []string `json:"interfaces"`
}
// configPath returns the path to nat.json next to the running binary.
func configPath() string {
exe, err := os.Executable()
if err != nil {
@@ -34,7 +28,6 @@ func IsInstalled() bool {
}
// Load reads the NAT config from disk.
// Returns an empty config if the file does not exist yet.
func Load() (*Config, error) {
data, err := os.ReadFile(configPath())
if err != nil {
@@ -53,7 +46,7 @@ func Load() (*Config, error) {
return &cfg, nil
}
// Save writes the NAT config to the configs/ directory next to the binary.
// Save writes the NAT config to the configs/ directory.
func Save(cfg *Config) error {
p := configPath()
if err := os.MkdirAll(filepath.Dir(p), 0755); err != nil {
@@ -65,59 +58,3 @@ func Save(cfg *Config) error {
}
return os.WriteFile(p, data, 0644)
}
// ApplyRules flushes the existing alpine-router NAT table and recreates it
// from the provided config. Called on every daemon startup and on config save.
//
// nftables is used instead of iptables because it applies all rules atomically
// in a single kernel call, which is faster and avoids partial-state issues.
func ApplyRules(cfg *Config) error {
return ApplyRulesWithBlocked(cfg, nil)
}
// ApplyRulesWithBlocked is like ApplyRules but also installs drop rules for
// the given list of blocked client IPs.
func ApplyRulesWithBlocked(cfg *Config, blockedIPs []string) error {
if err := os.WriteFile("/proc/sys/net/ipv4/ip_forward", []byte("1"), 0644); err != nil {
return fmt.Errorf("enable ip_forward: %w", err)
}
exec.Command("nft", "delete", "table", "ip", tableName).Run()
if len(cfg.Interfaces) == 0 && len(blockedIPs) == 0 {
return nil
}
var sb strings.Builder
fmt.Fprintf(&sb, "table ip %s {\n", tableName)
sb.WriteString(" chain forward {\n")
sb.WriteString(" type filter hook forward priority filter; policy drop;\n")
sb.WriteString(" ct state established,related accept\n")
for _, ip := range blockedIPs {
fmt.Fprintf(&sb, " ip saddr %s drop\n", ip)
fmt.Fprintf(&sb, " ip daddr %s drop\n", ip)
}
for _, iface := range cfg.Interfaces {
fmt.Fprintf(&sb, " iifname \"%s\" accept\n", iface)
}
sb.WriteString(" }\n")
sb.WriteString(" chain postrouting {\n")
sb.WriteString(" type nat hook postrouting priority srcnat; policy accept;\n")
for _, iface := range cfg.Interfaces {
fmt.Fprintf(&sb, " iifname \"%s\" masquerade\n", iface)
}
sb.WriteString(" }\n")
sb.WriteString("}\n")
cmd := exec.Command("nft", "-f", "-")
cmd.Stdin = strings.NewReader(sb.String())
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("nft apply: %s: %w", strings.TrimSpace(string(out)), err)
}
return nil
}