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 @@
-
-
-
-
-
-
-
+
+
+
+
+