mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-18 05:19:19 +08:00
fix: Fix the issue where deleting rules in iptables advanced settings… (#10942)
… fails
This commit is contained in:
parent
c4bd4734a5
commit
55cbf572e0
10 changed files with 108 additions and 97 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"`
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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": {},
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -26,18 +26,16 @@
|
|||
<el-input clearable v-model.trim="dialogData.rowData!.targetPort" />
|
||||
</el-form-item>
|
||||
|
||||
<template v-if="dialogData.fireName === 'ufw'">
|
||||
<el-form-item :label="$t('firewall.forwardInboundInterface')" prop="interface">
|
||||
<el-select class="w-full" v-model="dialogData.rowData!.interface">
|
||||
<el-option
|
||||
v-for="item in interfaceOptions"
|
||||
:key="item.value"
|
||||
:label="item.label === 'all' ? $t('commons.table.all') : item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<el-form-item :label="$t('firewall.forwardInboundInterface')" prop="interface">
|
||||
<el-select class="w-full" v-model="dialogData.rowData!.interface">
|
||||
<el-option
|
||||
v-for="item in interfaceOptions"
|
||||
:key="item.value"
|
||||
:label="item.label === 'all' ? $t('commons.table.all') : item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
|
|
@ -81,12 +79,10 @@ const acceptParams = (params: DialogProps): void => {
|
|||
if (dialogData.value.title === 'edit') {
|
||||
oldRule.value = deepCopy(params.rowData);
|
||||
}
|
||||
if (dialogData.value.fireName === 'ufw') {
|
||||
getNetworkOptions().then((res) => {
|
||||
interfaceOptions.value = res.data.map((item) => ({ label: item, value: item }));
|
||||
dialogData.value.rowData!.interface = dialogData.value.rowData!.interface || 'all';
|
||||
});
|
||||
}
|
||||
getNetworkOptions().then((res) => {
|
||||
interfaceOptions.value = res.data.map((item) => ({ label: item, value: item }));
|
||||
dialogData.value.rowData!.interface = dialogData.value.rowData!.interface || 'all';
|
||||
});
|
||||
title.value = i18n.global.t('firewall.' + dialogData.value.title);
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue