package iptables_helper import ( "context" "fmt" "strings" "time" "github.com/1Panel-dev/1Panel/agent/constant" "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/cmd" "github.com/1Panel-dev/1Panel/agent/utils/firewall/filter" "github.com/1Panel-dev/1Panel/agent/utils/firewall/lifecycle" ) const ( InputChain = "INPUT" BasicBeforeChain = constant.FirewallBasicBeforeChain BasicChain = constant.FirewallBasicChain BasicAfterChain = constant.FirewallBasicAfterChain ) func BasicChains() []string { return []string{BasicBeforeChain, BasicChain, BasicAfterChain} } const ( EstablishedRule = "-m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -m comment --comment \"ESTABLISHED Whitelist\"" IoRuleIn = "-i lo -j ACCEPT -m comment --comment \"Loopback Whitelist\"" DropAllTcp = "-p tcp -j DROP" DropAllUdp = "-p udp -j DROP" AllowSSH = "-p tcp --dport ssh -j ACCEPT" ) const ( ACCEPT = "ACCEPT" DROP = "DROP" REJECT = "REJECT" ANYWHERE = "anywhere" ) const ( FilterTab = "filter" NatTab = "nat" ) func runTables(ctx context.Context, executable, tab string, ignoreExist1, withWait bool, ruleArgs ...string) (string, error) { options := []cmd.Option{cmd.WithContext(ctx), cmd.WithTimeout(60 * time.Second)} if ignoreExist1 { options = append(options, cmd.WithIgnoreExist1()) } cmdMgr := cmd.NewCommandMgr(options...) args := []string{"-t", tab} if withWait { args = append(args, "-w") } args = append(args, ruleArgs...) stdout, err := cmdMgr.RunWithOptionalSudoAndStdout(executable, args...) if err != nil { return stdout, fmt.Errorf("command=%s %s failed: %w", executable, strings.Join(args, " "), err) } return stdout, nil } func runIptables(ctx context.Context, tab string, ignoreExist1, withWait bool, ruleArgs ...string) (string, error) { commands, err := lifecycle.ResolveIptablesCommands() if err != nil { return "", err } return runTables(ctx, commands.IPv4, tab, ignoreExist1, withWait, ruleArgs...) } func RunWithStd(tab string, args ...string) (string, error) { return RunWithStdContext(context.Background(), tab, args...) } func RunWithStdContext(ctx context.Context, tab string, args ...string) (string, error) { stdout, err := runIptables(ctx, tab, true, true, args...) if err != nil { global.LOG.Errorf("iptables command failed [table=%s, args=%s]: %v", tab, strings.Join(args, " "), err) return stdout, err } return stdout, nil } func RunIPv6WithStd(tab string, args ...string) (string, error) { return RunIPv6WithStdContext(context.Background(), tab, args...) } func RunIPv6WithStdContext(ctx context.Context, tab string, args ...string) (string, error) { commands, executableErr := lifecycle.ResolveIptablesCommands() if executableErr != nil { return "", executableErr } if !commands.IPv6Available() { return "", fmt.Errorf("%w: ip6tables/ip6tables-restore are not installed", filter.ErrFamilyUnavailable) } ignoreExist1 := len(args) == 0 || (args[0] != "-S" && args[0] != "-L" && args[0] != "-nL") stdout, err := runTables(ctx, commands.IPv6, tab, ignoreExist1, true, args...) if err != nil { if strings.Contains(err.Error(), "Address family not supported") || strings.Contains(err.Error(), "Protocol not supported") { return stdout, fmt.Errorf("%w: %v", filter.ErrFamilyUnavailable, err) } global.LOG.Errorf("ip6tables command failed [table=%s, args=%s]: %v", tab, strings.Join(args, " "), err) return stdout, err } return stdout, nil } func RunIPv6(tab string, args ...string) error { _, err := RunIPv6WithStd(tab, args...) return err } func CheckIPv6ChainExist(tab, chain string) (bool, error) { stdout, err := RunIPv6WithStd(tab, "-S") if err != nil { return false, fmt.Errorf("check IPv6 chain %s from tab %s exist failed: %w", chain, tab, err) } for _, line := range strings.Split(stdout, "\n") { if strings.TrimSpace(line) == "-N "+chain { return true, nil } } return false, nil } func Run(tab string, args ...string) error { if _, err := RunWithStd(tab, args...); err != nil { return err } return nil } func CheckChainExist(tab, chain string) (bool, error) { stdout, err := RunWithStd(tab, "-S") if err != nil { global.LOG.Errorf("check chain %s from tab %s exist failed, err: %v", chain, tab, err) return false, fmt.Errorf("check chain %s from tab %s exist failed, err: %v", chain, tab, err) } for _, line := range strings.Split(stdout, "\n") { if strings.TrimSpace(line) == "-N "+chain { return true, nil } } return false, nil } func ReadTable(ctx context.Context, table string, ipv6 bool) (string, error) { commands, err := lifecycle.ResolveIptablesCommands() if err != nil { return "", err } executable := commands.IPv4 if ipv6 { if !commands.IPv6Available() { return "", fmt.Errorf("%w: ip6tables/ip6tables-restore are not installed", filter.ErrFamilyUnavailable) } executable = commands.IPv6 } output, err := runTables(ctx, executable, table, false, true, "-S") if err != nil && ipv6 && (strings.Contains(err.Error(), "Address family not supported") || strings.Contains(err.Error(), "Protocol not supported")) { return output, fmt.Errorf("%w: %v", filter.ErrFamilyUnavailable, err) } return output, err }