From 55cbf572e01d316cba69db951f0ca24c98f1e0a4 Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Thu, 13 Nov 2025 14:38:47 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20Fix=20the=20issue=20where=20deleting=20r?= =?UTF-8?q?ules=20in=20iptables=20advanced=20settings=E2=80=A6=20(#10942)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … fails --- agent/app/service/firewall.go | 3 + agent/app/service/iptables.go | 32 +++++---- agent/utils/firewall/client/iptables.go | 32 ++------- .../utils/firewall/client/iptables/filter.go | 18 ++++- .../utils/firewall/client/iptables/forward.go | 65 +++++++++++-------- agent/utils/re/re.go | 2 - core/constant/common.go | 1 + frontend/src/api/interface/host.ts | 4 +- .../src/views/host/firewall/advance/index.vue | 16 ++--- .../host/firewall/forward/operate/index.vue | 32 ++++----- 10 files changed, 108 insertions(+), 97 deletions(-) diff --git a/agent/app/service/firewall.go b/agent/app/service/firewall.go index 4c060d68e..b6b566988 100644 --- a/agent/app/service/firewall.go +++ b/agent/app/service/firewall.go @@ -727,6 +727,9 @@ func (u *FirewallService) addPortRecord(req dto.PortRuleOperate) error { return nil } + if len(req.Description) == 0 { + return nil + } if err := hostRepo.SaveFirewallRecord(&model.Firewall{ Type: "port", Chain: req.Chain, diff --git a/agent/app/service/iptables.go b/agent/app/service/iptables.go index 249467d37..87e1952dd 100644 --- a/agent/app/service/iptables.go +++ b/agent/app/service/iptables.go @@ -64,11 +64,15 @@ func (s *IptablesService) Search(req dto.SearchPageWithType) (int64, interface{} } func (s *IptablesService) OperateRule(req dto.IptablesRuleOp) error { + action := "ACCEPT" + if req.Strategy == "drop" { + action = "DROP" + } policy := iptables.FilterRules{ Protocol: req.Protocol, SrcIP: req.SrcIP, DstIP: req.DstIP, - Strategy: req.Strategy, + Strategy: action, } if req.SrcPort != 0 { policy.SrcPort = fmt.Sprintf("%v", req.SrcPort) @@ -91,19 +95,21 @@ func (s *IptablesService) OperateRule(req dto.IptablesRuleOp) error { return fmt.Errorf("failed to add iptables rule: %w", err) } - rule := &model.Firewall{ - Chain: req.Chain, - Protocol: req.Protocol, - SrcIP: req.SrcIP, - SrcPort: fmt.Sprintf("%v", req.SrcPort), - DstIP: req.DstIP, - DstPort: fmt.Sprintf("%v", req.DstPort), - Strategy: req.Strategy, - Description: req.Description, - } + if len(req.Description) != 0 { + rule := &model.Firewall{ + Chain: req.Chain, + Protocol: req.Protocol, + SrcIP: req.SrcIP, + SrcPort: fmt.Sprintf("%v", req.SrcPort), + DstIP: req.DstIP, + DstPort: fmt.Sprintf("%v", req.DstPort), + Strategy: req.Strategy, + Description: req.Description, + } - if err := hostRepo.SaveFirewallRecord(rule); err != nil { - return fmt.Errorf("failed to save rule to database: %w", err) + if err := hostRepo.SaveFirewallRecord(rule); err != nil { + return fmt.Errorf("failed to save rule to database: %w", err) + } } case "remove": if err := iptables.DeleteFilterRule(req.Chain, policy); err != nil { diff --git a/agent/utils/firewall/client/iptables.go b/agent/utils/firewall/client/iptables.go index 5f7923f96..c847e2c6c 100644 --- a/agent/utils/firewall/client/iptables.go +++ b/agent/utils/firewall/client/iptables.go @@ -72,11 +72,6 @@ func (i *Iptables) ListPort() ([]FireInfo, error) { if item.Strategy == "drop" || item.Strategy == "reject" { item.Strategy = "drop" } - if item.Protocol == "6" { - item.Protocol = "tcp" - } else if item.Protocol == "17" { - item.Protocol = "udp" - } datas = append(datas, FireInfo{ Chain: item.Chain, @@ -263,30 +258,13 @@ func iptablesPortForward(info Forward, operation string) error { if err := iptables.AddForward(info.Protocol, info.Port, info.TargetIP, info.TargetPort, info.Interface, true); err != nil { return err } - forwardPersistence() - return nil - } - natList, err := iptables.ListForward(iptables.Chain1PanelPreRouting) - if err != nil { - return fmt.Errorf("failed to list NAT rules: %w", err) - } - - for _, nat := range natList { - if nat.Protocol == info.Protocol && - strings.TrimPrefix(nat.SrcPort, ":") == info.Port && - strings.TrimPrefix(nat.DestPort, ":") == info.TargetPort { - targetIP := info.TargetIP - if targetIP == "" { - targetIP = "127.0.0.1" - } - - if err := iptables.DeleteForward(nat.Num, info.Protocol, info.Port, targetIP, info.TargetPort, info.Interface); err != nil { - return err - } - forwardPersistence() + } else { + if err := iptables.DeleteForward(info.Num, info.Protocol, info.Port, info.TargetIP, info.TargetPort, info.Interface); err != nil { + return err } } - return fmt.Errorf("forward rule not found") + forwardPersistence() + return nil } func forwardPersistence() { diff --git a/agent/utils/firewall/client/iptables/filter.go b/agent/utils/firewall/client/iptables/filter.go index 64bdfd246..3b4e6d3fb 100644 --- a/agent/utils/firewall/client/iptables/filter.go +++ b/agent/utils/firewall/client/iptables/filter.go @@ -86,7 +86,7 @@ func ReadFilterRulesByChain(chain string) ([]FilterRules, error) { } itemRule := FilterRules{ Chain: chain, - Protocol: fields[1], + Protocol: loadProtocol(fields[1]), SrcPort: loadPort("src", fields), DstPort: loadPort("dst", fields), SrcIP: loadIP(fields[3]), @@ -135,6 +135,7 @@ func loadPort(position string, portStr []string) string { if strings.Contains(portStr[6], "dpts:") && position == "dst" { portItem = strings.ReplaceAll(portStr[6], "dpts:", "") } + portItem = strings.ReplaceAll(portItem, ":", "-") return portItem } @@ -145,6 +146,21 @@ func loadIP(ipStr string) string { return ipStr } +func loadProtocol(protocol string) string { + switch protocol { + case "0": + return "all" + case "1": + return "icmp" + case "6": + return "tcp" + case "17": + return "udp" + default: + return protocol + } +} + func validateRuleSafety(rule FilterRules, chain string) error { if strings.ToUpper(rule.Strategy) != "DROP" { return nil diff --git a/agent/utils/firewall/client/iptables/forward.go b/agent/utils/firewall/client/iptables/forward.go index 9925e5e80..c13ac0a54 100644 --- a/agent/utils/firewall/client/iptables/forward.go +++ b/agent/utils/firewall/client/iptables/forward.go @@ -3,8 +3,6 @@ package iptables import ( "fmt" "strings" - - "github.com/1Panel-dev/1Panel/agent/utils/re" ) func AddForward(protocol, srcPort, dest, destPort, iface string, save bool) error { @@ -71,42 +69,57 @@ func ListForward(chain ...string) ([]IptablesNatInfo, error) { if err != nil { return nil, err } - natListRegex := re.GetRegex(re.IptablesNatListPattern) var forwardList []IptablesNatInfo - for _, line := range strings.Split(stdout, "\n") { - line = strings.TrimFunc(line, func(r rune) bool { - return r <= 32 - }) - if natListRegex.MatchString(line) { - match := natListRegex.FindStringSubmatch(line) - if !strings.Contains(match[13], ":") { - match[13] = fmt.Sprintf(":%s", match[13]) - } - forwardList = append(forwardList, IptablesNatInfo{ - Num: match[1], - Target: match[4], - Protocol: match[11], - InIface: match[7], - OutIface: match[8], - Opt: match[6], - Source: match[9], - Destination: match[10], - SrcPort: match[12], - DestPort: match[13], - }) + lines := strings.Split(stdout, "\n") + for i := 0; i < len(lines); i++ { + fields := strings.Fields(lines[i]) + if len(fields) < 13 { + continue } + item := IptablesNatInfo{ + Num: fields[0], + Protocol: loadProtocol(fields[4]), + InIface: fields[6], + OutIface: fields[7], + Source: fields[8], + SrcPort: loadNatSrcPort(fields[11]), + } + if len(fields) == 15 && fields[13] == "ports" { + item.DestPort = fields[14] + } + if len(fields) == 13 && strings.HasPrefix(fields[12], "to:") { + parts := strings.Split(fields[12], ":") + if len(parts) > 2 { + item.DestPort = parts[2] + item.Destination = parts[1] + } + } + if len(item.Destination) == 0 { + item.Destination = "127.0.0.1" + } + forwardList = append(forwardList, item) } return forwardList, nil } +func loadNatSrcPort(portStr string) string { + var portItem string + if strings.Contains(portStr, "dpt:") { + portItem = strings.ReplaceAll(portStr, "dpt:", "") + } + if strings.Contains(portStr, "dpts:") { + portItem = strings.ReplaceAll(portStr, "dpts:", "") + } + portItem = strings.ReplaceAll(portItem, ":", "-") + return portItem +} + type IptablesNatInfo struct { Num string `json:"num"` - Target string `json:"target"` Protocol string `json:"protocol"` InIface string `json:"inIface"` OutIface string `json:"outIface"` - Opt string `json:"opt"` Source string `json:"source"` Destination string `json:"destination"` SrcPort string `json:"srcPort"` diff --git a/agent/utils/re/re.go b/agent/utils/re/re.go index be5540b5e..8519d0cfc 100644 --- a/agent/utils/re/re.go +++ b/agent/utils/re/re.go @@ -11,7 +11,6 @@ const ( ComposeEnvVarPattern = `\$\{([^}]+)\}` DiskKeyValuePattern = `([A-Za-z0-9_]+)=("([^"\\]|\\.)*"|[^ \t]+)` FirewalldForwardPattern = `^port=(\d{1,5}):proto=(.+?):toport=(\d{1,5}):toaddr=(.*)$` - IptablesNatListPattern = `^(\d+)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)(?:\s+(.+?) .+?:(\d{1,5}(?::\d+)?).+?[ :](.+-.+|(?:.+:)?\d{1,5}(?:-\d{1,5})?))?$` ValidatorNamePattern = `^[a-zA-Z\p{Han}]{1}[a-zA-Z0-9_\p{Han}]{0,30}$` ValidatorIPPattern = `^((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}$` DomainPattern = `^([\w\p{Han}\-\*]{1,100}\.){1,10}([\w\p{Han}\-]{1,24}|[\w\p{Han}\-]{1,24}\.[\w\p{Han}\-]{1,24})(:\d{1,5})?$` @@ -42,7 +41,6 @@ func Init() { ComposeEnvVarPattern, DiskKeyValuePattern, FirewalldForwardPattern, - IptablesNatListPattern, ValidatorNamePattern, ValidatorIPPattern, DomainPattern, diff --git a/core/constant/common.go b/core/constant/common.go index 99552f12e..2439cc83c 100644 --- a/core/constant/common.go +++ b/core/constant/common.go @@ -95,6 +95,7 @@ var WebUrlMap = map[string]struct{}{ "/hosts/firewall/port": {}, "/hosts/firewall/forward": {}, "/hosts/firewall/ip": {}, + "/hosts/firewall/advance": {}, "/hosts/process/process": {}, "/hosts/process/network": {}, "/hosts/ssh/ssh": {}, diff --git a/frontend/src/api/interface/host.ts b/frontend/src/api/interface/host.ts index 316826794..e35937c30 100644 --- a/frontend/src/api/interface/host.ts +++ b/frontend/src/api/interface/host.ts @@ -280,8 +280,8 @@ export namespace Host { export interface IptablesRules { id: number; protocol: string; - srcPort: number; - dstPort: number; + srcPort: string; + dstPort: string; srcIP: string; dstIP: string; strategy: string; diff --git a/frontend/src/views/host/firewall/advance/index.vue b/frontend/src/views/host/firewall/advance/index.vue index 07f9e49db..f9c2dd2ac 100644 --- a/frontend/src/views/host/firewall/advance/index.vue +++ b/frontend/src/views/host/firewall/advance/index.vue @@ -157,10 +157,10 @@ const opRef = ref(); const data = ref(); const formatPort = (port?: number | null | string) => { - if (port === 0 || port === '0') { + if (port === '' || port === 0 || port === '0') { return i18n.global.t('firewall.allPorts'); } - if (port === undefined || port === null || port === '') { + if (port === undefined || port === null) { return '-'; } return port; @@ -255,7 +255,7 @@ const onOpenDialog = async (title: string, rowData?: Host.IptablesFilterRuleOp) dialogRef.value!.acceptParams(params); }; -const onDelete = async (row: Host.IptablesFilterRuleOp | null) => { +const onDelete = async (row: Host.IptablesRules | null) => { let names = []; let rules = []; if (row) { @@ -263,8 +263,8 @@ const onDelete = async (row: Host.IptablesFilterRuleOp | null) => { operation: 'remove', id: row.id, chain: selectedChain.value, - srcPort: row.srcPort, - dstPort: row.dstPort, + srcPort: Number(row.srcPort), + dstPort: Number(row.dstPort), srcIP: row.srcIP === 'anywhere' ? '' : row.srcIP, dstIP: row.dstIP === 'anywhere' ? '' : row.dstIP, protocol: row.protocol, @@ -284,8 +284,8 @@ const onDelete = async (row: Host.IptablesFilterRuleOp | null) => { operation: 'remove', id: item.id, chain: selectedChain.value, - srcPort: item.srcPort, - dstPort: item.dstPort, + srcPort: Number(item.srcPort), + dstPort: Number(item.dstPort), srcIP: item.srcIP === 'anywhere' ? '' : item.srcIP, dstIP: item.dstIP === 'anywhere' ? '' : item.dstIP, protocol: item.protocol, @@ -305,7 +305,7 @@ const onDelete = async (row: Host.IptablesFilterRuleOp | null) => { const buttons = [ { label: i18n.global.t('commons.button.delete'), - click: (row: Host.IptablesFilterRuleOp) => { + click: (row: Host.IptablesRules) => { onDelete(row); }, }, diff --git a/frontend/src/views/host/firewall/forward/operate/index.vue b/frontend/src/views/host/firewall/forward/operate/index.vue index bed94982b..7514c6379 100644 --- a/frontend/src/views/host/firewall/forward/operate/index.vue +++ b/frontend/src/views/host/firewall/forward/operate/index.vue @@ -26,18 +26,16 @@ - + + + + +