Files
ssongliu e119239d3d refactor: manage firewall rules through runtime state and file backups (#13998)
Replace database rule synchronization with native rule operations and file-based backup, import, and recovery. Update firewall management views, descriptions, whitelist handling, and translations.

Include terminal reconnect fixes and xpack build tags for Darwin build targets. Remove temporary regression test files before committing.
2026-10-08 18:19:30 +08:00

103 lines
2.8 KiB
Go

package iptables_helper
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/1Panel-dev/1Panel/agent/constant"
"github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/utils/firewall"
"github.com/1Panel-dev/1Panel/agent/utils/firewall/filter"
"github.com/1Panel-dev/1Panel/agent/utils/firewall/lifecycle"
)
func RepairBaseChains(ports []firewall.PortWhitelist, families ...string) error {
if len(families) == 0 {
families = []string{constant.FirewallFamilyIPv4, constant.FirewallFamilyIPv6}
}
commands, err := lifecycle.ResolveIptablesCommands()
if err != nil {
return err
}
for _, family := range families {
ipv6 := family == constant.FirewallFamilyIPv6
run, executable := RunWithStd, commands.Restore4
if ipv6 {
if !commands.IPv6Available() {
continue
}
run, executable = RunIPv6WithStd, commands.Restore6
}
output, err := run(FilterTab, "-S")
if ipv6 && errors.Is(err, filter.ErrFamilyUnavailable) {
continue
}
if err != nil {
return err
}
script, err := buildBaseChainsRepairScript(global.Dir.FirewallDir, output, ipv6, func() ([]string, error) {
return baseDefaultRules(ports, family)
})
if err != nil {
return fmt.Errorf("prepare %s base chain repair: %w", family, err)
}
if script != "" {
if err := restoreRules(executable, script); err != nil {
return fmt.Errorf("repair %s base chains: %w", family, err)
}
}
}
return nil
}
func buildBaseChainsRepairScript(dir, output string, ipv6 bool, loadDefaults func() ([]string, error)) (string, error) {
var chains, rules, defaults []string
bound := true
for _, item := range []struct{ chain, file string }{
{BasicBeforeChain, BasicBeforeFileName},
{BasicChain, BasicFileName},
{BasicAfterChain, BasicAfterFileName},
} {
bound = bound && containsIptablesRule(output, "-A "+InputChain+" -j "+item.chain)
if containsIptablesRule(output, "-N "+item.chain) {
continue
}
chains = append(chains, "-N "+item.chain)
fileName := item.file
if ipv6 {
fileName = IPv6FileName(fileName)
}
data, err := os.ReadFile(filepath.Join(dir, fileName))
if err != nil && !errors.Is(err, os.ErrNotExist) {
return "", err
}
lines := strings.Split(string(data), "\n")
if errors.Is(err, os.ErrNotExist) && item.chain != BasicChain {
if defaults == nil {
defaults, err = loadDefaults()
if err != nil {
return "", err
}
}
lines = defaults
}
for _, line := range lines {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, "-A "+item.chain+" ") && !strings.ContainsAny(line, "\r\n") {
rules = append(rules, line)
}
}
}
lines := append(chains, rules...)
if !bound {
lines = append(lines, baseChainBindingCommands(output, true)...)
}
if len(lines) == 0 {
return "", nil
}
return "*filter\n" + strings.Join(lines, "\n") + "\nCOMMIT\n", nil
}