fix: display iptables default allowed ports (#10922)

This commit is contained in:
ssongliu 2025-11-11 22:22:42 +08:00 committed by GitHub
parent ffc81ea85a
commit 102f7c316d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 127 additions and 129 deletions

View file

@ -26,6 +26,7 @@ type FirewallOperation struct {
type PortRuleOperate struct {
ID uint `json:"id"`
Operation string `json:"operation" validate:"required,oneof=add remove"`
Chain string `json:"chain"`
Address string `json:"address"`
Port string `json:"port" validate:"required"`
Protocol string `json:"protocol" validate:"required,oneof=tcp udp tcp/udp"`
@ -89,7 +90,7 @@ type IptablesOp struct {
type IptablesRuleOp struct {
Operation string `json:"operation" validate:"required,oneof=add remove"`
ID uint `json:"id"`
Chain string `json:"chain" validate:"required,oneof=1PANEL_INPUT 1PANEL_OUTPUT"`
Chain string `json:"chain" validate:"required,oneof=1PANEL_BASIC 1PANEL_BASIC_BEFORE 1PANEL_INPUT 1PANEL_OUTPUT"`
Protocol string `json:"protocol"`
SrcIP string `json:"srcIP"`
SrcPort uint `json:"srcPort"`

View file

@ -232,9 +232,8 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
if err != nil {
return err
}
chain := ""
if client.Name() == "iptables" {
chain = iptables.Chain1PanelBasic
if len(req.Chain) == 0 && client.Name() == "iptables" {
req.Chain = iptables.Chain1PanelBasic
}
protos := strings.Split(req.Protocol, "/")
itemAddress := strings.Split(strings.TrimSuffix(req.Address, ","), ",")
@ -253,7 +252,7 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
return err
}
req.Port = strings.ReplaceAll(req.Port, ":", "-")
if err := u.addPortRecord(chain, req); err != nil {
if err := u.addPortRecord(req); err != nil {
return err
}
}
@ -274,7 +273,7 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
if len(req.Protocol) == 0 {
req.Protocol = "tcp/udp"
}
if err := u.addPortRecord(chain, req); err != nil {
if err := u.addPortRecord(req); err != nil {
return err
}
}
@ -290,7 +289,7 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
if err := u.operatePort(client, req); err != nil {
return err
}
if err := u.addPortRecord(chain, req); err != nil {
if err := u.addPortRecord(req); err != nil {
return err
}
}
@ -307,7 +306,7 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool)
if err := u.operatePort(client, req); err != nil {
return err
}
if err := u.addPortRecord(chain, req); err != nil {
if err := u.addPortRecord(req); err != nil {
return err
}
}
@ -707,7 +706,7 @@ func (u *FirewallService) addPortsBeforeStart(client firewall.FirewallClient) er
}
}
}
if err := client.Port(fireClient.FireInfo{Port: "22", Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
if err := client.Port(fireClient.FireInfo{Port: loadSSHPort(), Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
return err
}
if err := client.Port(fireClient.FireInfo{Port: "80", Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
@ -720,7 +719,7 @@ func (u *FirewallService) addPortsBeforeStart(client firewall.FirewallClient) er
return client.Reload()
}
func (u *FirewallService) addPortRecord(chain string, req dto.PortRuleOperate) error {
func (u *FirewallService) addPortRecord(req dto.PortRuleOperate) error {
if req.Operation == "remove" {
if req.ID != 0 {
return hostRepo.DeleteFirewallRecordByID(req.ID)
@ -729,7 +728,7 @@ func (u *FirewallService) addPortRecord(chain string, req dto.PortRuleOperate) e
if err := hostRepo.SaveFirewallRecord(&model.Firewall{
Type: "port",
Chain: chain,
Chain: req.Chain,
DstPort: req.Port,
Protocol: req.Protocol,
SrcIP: req.Address,
@ -821,7 +820,7 @@ func checkPortUsed(ports, proto string, apps []portOfApp) string {
}
func loadInitStatus(clientName, tab string) (bool, bool) {
if clientName != "iptables" && tab != "forward" {
if clientName != "firewalld" || (clientName != "iptables" && tab != "forward") {
return true, true
}
switch tab {

View file

@ -310,11 +310,11 @@ func initPreRules() error {
if len(panelPort) == 0 {
return errors.New("find 1panel service port failed")
}
if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasicBefore, iptables.AllowSSH); err != nil {
return err
}
if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasicBefore, fmt.Sprintf("-p tcp -m tcp --dport %s -j ACCEPT", panelPort)); err != nil {
return err
ports := []string{"80", "443", panelPort, loadSSHPort()}
for _, item := range ports {
if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasicBefore, fmt.Sprintf("-p tcp -m tcp --dport %v -j ACCEPT", item)); err != nil {
return err
}
}
if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasicAfter, iptables.DropAll); err != nil {
return err

View file

@ -887,3 +887,22 @@ func updateSSHSocketFile(newPort string) error {
_ = controller.HandleRestart("ssh.socket")
return nil
}
func loadSSHPort() string {
port := "22"
sshConf, err := os.ReadFile(sshPath)
if err != nil {
return port
}
lines := strings.Split(string(sshConf), "\n")
for _, line := range lines {
if strings.HasPrefix(line, "Port ") {
portStr := strings.ReplaceAll(line, "Port ", "")
portItem, _ := strconv.Atoi(portStr)
if portItem > 0 && portItem < 65535 {
return portStr
}
}
}
return port
}

View file

@ -3,7 +3,6 @@ package firewall
import (
"github.com/1Panel-dev/1Panel/agent/utils/firewall"
"github.com/1Panel-dev/1Panel/agent/utils/firewall/client/iptables"
"github.com/1Panel-dev/1Panel/agent/utils/re"
)
func Init() {
@ -11,8 +10,6 @@ func Init() {
if err != nil {
return
}
re.RegisterRegex(iptables.Chian1PanelBasicPortPattern)
re.RegisterRegex(iptables.Chain1PanelBasicAddressPattern)
clientName := client.Name()
if clientName == "ufw" || clientName == "iptables" {
_ = iptables.LoadRulesFromFile(iptables.FilterTab, iptables.Chain1PanelForward, iptables.ForwardFileName)

View file

@ -1,7 +1,8 @@
package client
type FireInfo struct {
ID uint `json:"uint"`
ID uint `json:"id"`
Chain string `json:"chain"`
Family string `json:"family"` // ipv4 ipv6
Address string `json:"address"` // Anywhere
Port string `json:"port"`

View file

@ -9,7 +9,6 @@ import (
"github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
"github.com/1Panel-dev/1Panel/agent/utils/firewall/client/iptables"
"github.com/1Panel-dev/1Panel/agent/utils/re"
)
type Iptables struct{}
@ -59,91 +58,52 @@ func (i *Iptables) Version() (string, error) {
}
func (i *Iptables) ListPort() ([]FireInfo, error) {
stdout, err := iptables.RunWithStd(iptables.FilterTab, fmt.Sprintf("-S %s", iptables.Chain1PanelBasic))
if err != nil {
return nil, fmt.Errorf("failed to list 1PANEL_BASIC rules: %w", err)
}
var datas []FireInfo
lines := strings.Split(stdout, "\n")
chainPortRegex := re.GetRegex(iptables.Chian1PanelBasicPortPattern)
for _, line := range lines {
line = strings.TrimSpace(line)
if !strings.HasPrefix(line, fmt.Sprintf("-A %s", iptables.Chain1PanelBasic)) {
basicRules, err := iptables.ReadFilterRulesByChain(iptables.Chain1PanelBasic)
if err != nil {
return nil, err
}
beforeRules, _ := iptables.ReadFilterRulesByChain(iptables.Chain1PanelBasicBefore)
basicRules = append(basicRules, beforeRules...)
for _, item := range basicRules {
if item.DstPort == 0 {
continue
}
if matches := chainPortRegex.FindStringSubmatch(line); len(matches) == 5 {
address := matches[1]
protocol := matches[2]
port := strings.ReplaceAll(matches[3], ":", "-")
action := strings.ToLower(matches[4])
strategy := "accept"
if action == "drop" || action == "reject" {
strategy = "drop"
}
datas = append(datas, FireInfo{
Address: address,
Protocol: protocol,
Port: port,
Strategy: strategy,
Family: "ipv4",
})
if item.Strategy == "drop" || item.Strategy == "reject" {
item.Strategy = "drop"
}
datas = append(datas, FireInfo{
Chain: item.Chain,
Address: item.SrcIP,
Protocol: item.Protocol,
Port: fmt.Sprintf("%v", item.DstPort),
Strategy: item.Strategy,
Family: "ipv4",
})
}
return datas, nil
}
func (i *Iptables) ListAddress() ([]FireInfo, error) {
stdout, err := iptables.RunWithStd(iptables.FilterTab, fmt.Sprintf("-S %s", iptables.Chain1PanelBasic))
if err != nil {
return nil, fmt.Errorf("failed to list 1PANEL_BASIC address rules: %w", err)
}
var datas []FireInfo
lines := strings.Split(stdout, "\n")
addressMap := make(map[string]FireInfo)
chainAddressRegex := re.GetRegex(iptables.Chain1PanelBasicAddressPattern)
for _, line := range lines {
line = strings.TrimSpace(line)
if !strings.HasPrefix(line, fmt.Sprintf("-A %s", iptables.Chain1PanelBasic)) {
basicRules, err := iptables.ReadFilterRulesByChain(iptables.Chain1PanelBasic)
if err != nil {
return nil, err
}
for _, item := range basicRules {
if item.DstPort != 0 || item.SrcPort != 0 {
continue
}
if matches := chainAddressRegex.FindStringSubmatch(line); len(matches) >= 4 {
address := matches[1]
if address == "" {
address = matches[2]
}
if address == "" {
continue
}
action := strings.ToLower(matches[3])
strategy := "accept"
if action == "drop" || action == "reject" {
strategy = "drop"
}
if _, exists := addressMap[address]; !exists {
addressMap[address] = FireInfo{
Address: address,
Strategy: strategy,
Family: "ipv4",
}
}
if item.Strategy == "drop" || item.Strategy == "reject" {
item.Strategy = "drop"
}
datas = append(datas, FireInfo{
Address: item.SrcIP,
Strategy: item.Strategy,
Family: "ipv4",
})
}
for _, info := range addressMap {
datas = append(datas, info)
}
return datas, nil
}
@ -151,6 +111,9 @@ func (i *Iptables) Port(port FireInfo, operation string) error {
if operation != "add" && operation != "remove" {
return buserr.New("ErrCmdIllegal")
}
if len(port.Chain) == 0 {
port.Chain = iptables.Chain1PanelBasic
}
portSpec, err := normalizePortSpec(port.Port)
if err != nil {
@ -174,17 +137,19 @@ func (i *Iptables) Port(port FireInfo, operation string) error {
ruleArgs = append(ruleArgs, fmt.Sprintf("--dport %s", portSpec), fmt.Sprintf("-j %s", action))
ruleSpec := strings.Join(ruleArgs, " ")
if operation == "add" {
if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasic, ruleSpec); err != nil {
if err := iptables.AddRule(iptables.FilterTab, port.Chain, ruleSpec); err != nil {
return err
}
} else {
if err := iptables.DeleteRule(iptables.FilterTab, iptables.Chain1PanelBasic, ruleSpec); err != nil {
if err := iptables.DeleteRule(iptables.FilterTab, port.Chain, ruleSpec); err != nil {
return err
}
}
if err := iptables.SaveRulesToFile(iptables.FilterTab, iptables.Chain1PanelBasic, iptables.BasicFileName); err != nil {
global.LOG.Errorf("persistence for %s failed, err: %v", iptables.Chain1PanelBasic, err)
if port.Chain == iptables.Chain1PanelBasic {
if err := iptables.SaveRulesToFile(iptables.FilterTab, iptables.Chain1PanelBasic, iptables.BasicFileName); err != nil {
global.LOG.Errorf("persistence for %s failed, err: %v", iptables.Chain1PanelBasic, err)
}
}
return nil
}
@ -193,6 +158,9 @@ func (i *Iptables) RichRules(rule FireInfo, operation string) error {
if operation != "add" && operation != "remove" {
return buserr.New("ErrCmdIllegal")
}
if len(rule.Chain) == 0 {
rule.Chain = iptables.Chain1PanelBasic
}
address := strings.TrimSpace(rule.Address)
if strings.EqualFold(address, "Anywhere") {
@ -235,17 +203,19 @@ func (i *Iptables) RichRules(rule FireInfo, operation string) error {
ruleArgs = append(ruleArgs, fmt.Sprintf("-j %s", action))
ruleSpec := strings.Join(ruleArgs, " ")
if operation == "add" {
if err := iptables.AddRule(iptables.FilterTab, iptables.Chain1PanelBasic, ruleSpec); err != nil {
if err := iptables.AddRule(iptables.FilterTab, rule.Chain, ruleSpec); err != nil {
return err
}
} else {
if err := iptables.DeleteRule(iptables.FilterTab, iptables.Chain1PanelBasic, ruleSpec); err != nil {
if err := iptables.DeleteRule(iptables.FilterTab, rule.Chain, ruleSpec); err != nil {
return err
}
}
if err := iptables.SaveRulesToFile(iptables.FilterTab, iptables.Chain1PanelBasic, iptables.BasicFileName); err != nil {
global.LOG.Errorf("persistence for %s failed, err: %v", iptables.Chain1PanelBasic, err)
if rule.Chain == iptables.Chain1PanelBasic {
if err := iptables.SaveRulesToFile(iptables.FilterTab, iptables.Chain1PanelBasic, iptables.BasicFileName); err != nil {
global.LOG.Errorf("persistence for %s failed, err: %v", iptables.Chain1PanelBasic, err)
}
}
return nil
}

View file

@ -42,11 +42,6 @@ const (
NatTab = "nat"
)
var (
Chain1PanelBasicAddressPattern = fmt.Sprintf(`-A\s+%s\s+(?:-s\s+(\S+)|(?:-d\s+(\S+)))?\s+-j\s+(\w+)`, Chain1PanelBasic)
Chian1PanelBasicPortPattern = fmt.Sprintf(`-A\s+%s\s+(?:-s\s+(\S+)\s+)?-p\s+(\w+)(?:\s+-m\s+\w+)*\s+--dport\s+(\d+(?::\d+)?)\s+-j\s+(\w+)`, Chain1PanelBasic)
)
func RunWithStd(tab, rule string) (string, error) {
cmdMgr := cmd.NewCommandMgr(cmd.WithIgnoreExist1(), cmd.WithTimeout(20*time.Second))
stdout, err := cmdMgr.RunWithStdoutBashCf("%s iptables -t %s %s", cmd.SudoHandleCmd(), tab, rule)
@ -56,7 +51,7 @@ func RunWithStd(tab, rule string) (string, error) {
}
return stdout, nil
}
func RunWithoutIgnrore(tab, rule string) (string, error) {
func RunWithoutIgnore(tab, rule string) (string, error) {
cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(20 * time.Second))
stdout, err := cmdMgr.RunWithStdoutBashCf("%s iptables -t %s %s", cmd.SudoHandleCmd(), tab, rule)
if err != nil {
@ -112,7 +107,7 @@ func CheckChainBind(tab, parentChain, chain string) (bool, error) {
return true, nil
}
func CheckRuleExist(tab, chain, rule string) bool {
_, err := RunWithoutIgnrore(tab, fmt.Sprintf("-C %s %s", chain, rule))
_, err := RunWithoutIgnore(tab, fmt.Sprintf("-C %s %s", chain, rule))
return err == nil
}

View file

@ -11,6 +11,7 @@ import (
type FilterRules struct {
ID uint `json:"id"`
Chain string `json:"chain"`
Protocol string `json:"protocol"`
SrcPort uint `json:"srcPort"`
DstPort uint `json:"dstPort"`
@ -70,23 +71,28 @@ func DeleteFilterRule(chain string, policy FilterRules) error {
func ReadFilterRulesByChain(chain string) ([]FilterRules, error) {
var rules []FilterRules
cmdMgr := cmd.NewCommandMgr(cmd.WithIgnoreExist1(), cmd.WithTimeout(20*time.Second))
stdout, err := cmdMgr.RunWithStdoutBashCf("%s iptables -t %s -L %s", cmd.SudoHandleCmd(), FilterTab, chain)
stdout, err := cmdMgr.RunWithStdoutBashCf("%s iptables -w -t %s -nL %s", cmd.SudoHandleCmd(), FilterTab, chain)
if err != nil {
return rules, fmt.Errorf("load filter fules by chain %s failed, %v", chain, err)
}
lines := strings.Split(stdout, "\n")
for i := 0; i < len(lines); i++ {
fields := strings.Fields(lines[i])
if len(fields) < 7 {
if len(fields) < 5 {
continue
}
strategy := strings.ToLower(fields[0])
if strategy != "accept" && strategy != "drop" && strategy != "reject" {
continue
}
itemRule := FilterRules{
Chain: chain,
Protocol: fields[1],
SrcPort: loadPort("src", fields[6]),
DstPort: loadPort("dst", fields[6]),
SrcPort: loadPort("src", fields),
DstPort: loadPort("dst", fields),
SrcIP: loadIP(fields[3]),
DstIP: loadIP(fields[4]),
Strategy: fields[0],
Strategy: strategy,
}
rules = append(rules, itemRule)
}
@ -95,7 +101,7 @@ func ReadFilterRulesByChain(chain string) ([]FilterRules, error) {
func LoadDefaultStrategy(chain string) (string, error) {
cmdMgr := cmd.NewCommandMgr(cmd.WithIgnoreExist1(), cmd.WithTimeout(20*time.Second))
stdout, err := cmdMgr.RunWithStdoutBashCf("%s iptables -t %s -L %s", cmd.SudoHandleCmd(), FilterTab, chain)
stdout, err := cmdMgr.RunWithStdoutBashCf("%s iptables -w -t %s -L %s", cmd.SudoHandleCmd(), FilterTab, chain)
if err != nil {
return "", fmt.Errorf("load filter fules by chain %s failed, %v", chain, err)
}
@ -112,13 +118,17 @@ func LoadDefaultStrategy(chain string) (string, error) {
return ACCEPT, nil
}
func loadPort(position, portStr string) uint {
var portItem string
if strings.Contains(portStr, "spt:") && position == "src" {
portItem = strings.ReplaceAll(portStr, "spt:", "")
func loadPort(position string, portStr []string) uint {
if len(portStr) < 7 {
return 0
}
if strings.Contains(portStr, "dpt:") && position == "dst" {
portItem = strings.ReplaceAll(portStr, "dpt:", "")
var portItem string
if strings.Contains(portStr[6], "spt:") && position == "src" {
portItem = strings.ReplaceAll(portStr[6], "spt:", "")
}
if strings.Contains(portStr[6], "dpt:") && position == "dst" {
portItem = strings.ReplaceAll(portStr[6], "dpt:", "")
}
if len(portItem) == 0 {
return 0

View file

@ -90,7 +90,7 @@ const acceptParams = (params: DialogProps) => {
uploaderFiles.value = [];
uploadRef.value?.clearFiles();
isImport.value = params?.isImport;
withoutReload.value = params.withoutReload;
withoutReload.value = params?.withoutReload;
open.value = true;
};

View file

@ -5,7 +5,7 @@
<div v-loading="loading">
<FireStatus
ref="fireStatusRef"
@search="search"
@search="search(true)"
v-model:loading="loading"
v-model:name="fireName"
v-model:mask-show="maskShow"
@ -64,7 +64,7 @@
:heightDiff="370"
>
<el-table-column type="selection" fix />
<el-table-column :min-width="80" :label="$t('firewall.address')" prop="address">
<el-table-column :min-width="120" :label="$t('firewall.address')" prop="address">
<template #default="{ row }">
<span v-if="row.address && row.address !== 'Anywhere'">{{ row.address }}</span>
<span v-else>{{ $t('firewall.allIP') }}</span>
@ -86,7 +86,7 @@
</template>
</el-table-column>
<el-table-column
:min-width="150"
:min-width="120"
:label="$t('commons.table.description')"
prop="description"
show-overflow-tooltip
@ -156,7 +156,7 @@ const paginationConfig = reactive({
total: 0,
});
const search = async () => {
const search = async (init?: boolean) => {
if (!isActive.value) {
loading.value = false;
data.value = [];
@ -172,7 +172,9 @@ const search = async () => {
pageSize: paginationConfig.pageSize,
};
loading.value = true;
loadStatus();
if (init) {
loadStatus();
}
await searchFireRule(params)
.then((res) => {
loading.value = false;

View file

@ -5,7 +5,7 @@
<div v-loading="loading">
<FireStatus
ref="fireStatusRef"
@search="search"
@search="search(true)"
v-model:loading="loading"
v-model:mask-show="maskShow"
v-model:is-active="isActive"
@ -207,7 +207,7 @@ const paginationConfig = reactive({
total: 0,
});
const search = async () => {
const search = async (init?: boolean) => {
if (!isActive.value) {
loading.value = false;
data.value = [];
@ -223,7 +223,9 @@ const search = async () => {
pageSize: paginationConfig.pageSize,
};
loading.value = true;
loadStatus();
if (init) {
loadStatus();
}
await searchFireRule(params)
.then((res) => {
loading.value = false;
@ -322,6 +324,7 @@ const onDelete = async (row: Host.RuleInfo | null) => {
if (row) {
rules.push({
operation: 'remove',
chain: row.chain,
address: row.address,
port: row.port,
source: '',
@ -334,6 +337,7 @@ const onDelete = async (row: Host.RuleInfo | null) => {
names.push(item.port + ' (' + item.protocol + ')');
rules.push({
operation: 'remove',
chain: item.chain,
address: item.address,
port: item.port,
source: '',

View file

@ -27,7 +27,7 @@
{{ $t('commons.button.init') }}
</el-button>
</template>
<template v-if="baseInfo.isInit && props.currentTab == 'base'">
<template v-if="baseInfo.name === 'iptables' && baseInfo.isInit && props.currentTab == 'base'">
<el-divider direction="vertical" />
<el-button v-if="baseInfo.isBind" type="primary" link @click="onUnBind">
{{ $t('commons.button.unbind') }}