mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-09-23 00:00:52 +00:00
103 lines
2.6 KiB
Go
103 lines
2.6 KiB
Go
package nftables_helper
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/1Panel-dev/1Panel/agent/global"
|
|
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
|
|
"github.com/1Panel-dev/1Panel/agent/utils/firewall/filter"
|
|
)
|
|
|
|
const RulesFile = "1panel_filter.nft"
|
|
|
|
func PersistRuleset(ctx context.Context) error {
|
|
var ruleset strings.Builder
|
|
run := cmd.NewCommandMgr(cmd.WithContext(ctx), cmd.WithTimeout(60*time.Second))
|
|
for _, family := range []filter.Family{filter.FamilyIPv4, filter.FamilyIPv6} {
|
|
stdout, exists, err := readNftObject(func(args ...string) (string, error) {
|
|
return run.RunWithOptionalSudoAndStdout("nft", args...)
|
|
}, "list", "table", TableFamily(family), TableName)
|
|
if family == filter.FamilyIPv6 && errors.Is(err, filter.ErrFamilyUnavailable) {
|
|
continue
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !exists {
|
|
continue
|
|
}
|
|
ruleset.WriteString(stdout)
|
|
if !strings.HasSuffix(stdout, "\n") {
|
|
ruleset.WriteByte('\n')
|
|
}
|
|
}
|
|
return atomicWrite(filepath.Join(global.Dir.FirewallDir, RulesFile), []byte(ruleset.String()))
|
|
}
|
|
|
|
func Restore() error {
|
|
file := filepath.Join(global.Dir.FirewallDir, RulesFile)
|
|
if _, err := os.Stat(file); errors.Is(err, os.ErrNotExist) {
|
|
return nil
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
existing := make([]string, 0, 2)
|
|
for _, family := range []filter.Family{filter.FamilyIPv4, filter.FamilyIPv6} {
|
|
tableFamily := TableFamily(family)
|
|
_, exists, err := readNftObject(run, "list", "table", tableFamily, TableName)
|
|
if family == filter.FamilyIPv6 && errors.Is(err, filter.ErrFamilyUnavailable) {
|
|
continue
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if exists {
|
|
existing = append(existing, tableFamily)
|
|
}
|
|
}
|
|
if len(existing) == 2 {
|
|
return nil
|
|
}
|
|
for _, tableFamily := range existing {
|
|
if _, err := run("delete", "table", tableFamily, TableName); err != nil {
|
|
return fmt.Errorf("remove partial nftables %s table before restore: %w", tableFamily, err)
|
|
}
|
|
}
|
|
return runCommand("-f", file)
|
|
}
|
|
|
|
func atomicWrite(target string, data []byte) error {
|
|
file, err := os.CreateTemp(filepath.Dir(target), ".nft-rules-*")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
temporary := file.Name()
|
|
committed := false
|
|
defer func() {
|
|
_ = file.Close()
|
|
if !committed {
|
|
_ = os.Remove(temporary)
|
|
}
|
|
}()
|
|
if _, err := file.Write(data); err != nil {
|
|
return err
|
|
}
|
|
if err := file.Sync(); err != nil {
|
|
return err
|
|
}
|
|
if err := file.Close(); err != nil {
|
|
return err
|
|
}
|
|
if err := os.Rename(temporary, target); err != nil {
|
|
return fmt.Errorf("replace nftables rules file: %w", err)
|
|
}
|
|
committed = true
|
|
return nil
|
|
}
|