2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 06:47:20 +08:00

fix: 罕见情况下防火墙规则错误

This commit is contained in:
耗子
2024-10-23 03:05:40 +08:00
parent 3c72a66c1f
commit fc1584e7da
10 changed files with 78 additions and 20 deletions

View File

@@ -78,6 +78,7 @@ func (s *Service) UpdatePort(w http.ResponseWriter, r *http.Request) {
fw := firewall.NewFirewall()
err = fw.Port(firewall.FireInfo{
Type: firewall.TypeNormal,
PortStart: req.Port,
PortEnd: req.Port,
Direction: firewall.DirectionIn,

View File

@@ -156,6 +156,7 @@ func (s *Service) UpdatePort(w http.ResponseWriter, r *http.Request) {
fw := firewall.NewFirewall()
err = fw.Port(firewall.FireInfo{
Type: firewall.TypeNormal,
PortStart: req.Port,
PortEnd: req.Port,
Direction: firewall.DirectionIn,

View File

@@ -205,6 +205,7 @@ func (r *settingRepo) UpdatePanelSetting(ctx context.Context, setting *request.P
// 放行端口
fw := firewall.NewFirewall()
err = fw.Port(firewall.FireInfo{
Type: firewall.TypeNormal,
PortStart: uint(config.HTTP.Port),
PortEnd: uint(config.HTTP.Port),
Direction: firewall.DirectionIn,

View File

@@ -5,6 +5,7 @@ type FirewallStatus struct {
}
type FirewallRule struct {
Type string `json:"type"`
Family string `json:"family" validate:"required,oneof=ipv4 ipv6"`
PortStart uint `json:"port_start" validate:"required,gte=1,lte=65535"`
PortEnd uint `json:"port_end" validate:"required,gte=1,lte=65535"`

View File

@@ -86,6 +86,7 @@ func (s *FirewallService) GetRules(w http.ResponseWriter, r *http.Request) {
}
}
filledRules = append(filledRules, map[string]any{
"type": rule.Type,
"family": rule.Family,
"port_start": rule.PortStart,
"port_end": rule.PortEnd,
@@ -113,7 +114,7 @@ func (s *FirewallService) CreateRule(w http.ResponseWriter, r *http.Request) {
}
if err = s.firewall.Port(firewall.FireInfo{
Family: req.Family, PortStart: req.PortStart, PortEnd: req.PortEnd, Protocol: firewall.Protocol(req.Protocol), Address: req.Address, Strategy: firewall.Strategy(req.Strategy), Direction: firewall.Direction(req.Direction),
Type: firewall.Type(req.Type), Family: req.Family, PortStart: req.PortStart, PortEnd: req.PortEnd, Protocol: firewall.Protocol(req.Protocol), Address: req.Address, Strategy: firewall.Strategy(req.Strategy), Direction: firewall.Direction(req.Direction),
}, firewall.OperationAdd); err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
return
@@ -130,7 +131,7 @@ func (s *FirewallService) DeleteRule(w http.ResponseWriter, r *http.Request) {
}
if err = s.firewall.Port(firewall.FireInfo{
Family: req.Family, PortStart: req.PortStart, PortEnd: req.PortEnd, Protocol: firewall.Protocol(req.Protocol), Address: req.Address, Strategy: firewall.Strategy(req.Strategy), Direction: firewall.Direction(req.Direction),
Type: firewall.Type(req.Type), Family: req.Family, PortStart: req.PortStart, PortEnd: req.PortEnd, Protocol: firewall.Protocol(req.Protocol), Address: req.Address, Strategy: firewall.Strategy(req.Strategy), Direction: firewall.Direction(req.Direction),
}, firewall.OperationRemove); err != nil {
Error(w, http.StatusInternalServerError, "%v", err)
return

View File

@@ -7,6 +7,13 @@ var (
OperationRemove Operation = "remove" // 移除
)
type Type string
var (
TypeRich Type = "rich" // rich
TypeNormal Type = "normal" // normal
)
type Protocol string
var (
@@ -31,6 +38,7 @@ var (
)
type FireInfo struct {
Type Type `json:"type"` // rich or normal
Family string `json:"family"` // ipv4 ipv6
Address string `json:"address"` // 源地址或目标地址
PortStart uint `json:"port_start"` // 1-65535

View File

@@ -54,6 +54,7 @@ func (r *Firewall) ListRule() ([]FireInfo, error) {
continue
}
var item FireInfo
item.Type = TypeNormal
if strings.Contains(port, "/") {
ruleItem := strings.Split(port, "/")
portItem := strings.Split(ruleItem[0], "-")
@@ -82,6 +83,32 @@ func (r *Firewall) ListRule() ([]FireInfo, error) {
}()
wg.Wait()
slices.SortFunc(data, func(a FireInfo, b FireInfo) int {
if a.PortStart != b.PortStart {
return int(a.PortStart - b.PortStart)
}
if a.PortEnd != b.PortEnd {
return int(a.PortEnd - b.PortEnd)
}
if a.Protocol != b.Protocol {
return strings.Compare(string(a.Protocol), string(b.Protocol))
}
if a.Family != b.Family {
return strings.Compare(a.Family, b.Family)
}
if a.Strategy != b.Strategy {
return strings.Compare(string(a.Strategy), string(b.Strategy))
}
if a.Direction != b.Direction {
return strings.Compare(string(a.Direction), string(b.Direction))
}
if a.Type != b.Type {
return strings.Compare(string(a.Type), string(b.Type))
}
return 0
})
return data, nil
}
@@ -113,6 +140,22 @@ func (r *Firewall) ListForward() ([]FireForwardInfo, error) {
}
}
slices.SortFunc(data, func(a FireForwardInfo, b FireForwardInfo) int {
if a.Port != b.Port {
return int(a.Port - b.Port)
}
if a.TargetPort != b.TargetPort {
return int(a.TargetPort - b.TargetPort)
}
if a.Protocol != b.Protocol {
return strings.Compare(string(a.Protocol), string(b.Protocol))
}
if a.TargetIP != b.TargetIP {
return strings.Compare(a.TargetIP, b.TargetIP)
}
return 0
})
return data, nil
}
@@ -144,7 +187,7 @@ func (r *Firewall) Port(rule FireInfo, operation Operation) error {
return fmt.Errorf("invalid port range: %d-%d", rule.PortStart, rule.PortEnd)
}
// 不支持的切换使用rich rules
if (rule.Family != "" && rule.Family != "ipv4") || rule.Direction != "in" || rule.Address != "" || rule.Strategy != "accept" {
if (rule.Family != "" && rule.Family != "ipv4") || rule.Direction != "in" || rule.Address != "" || rule.Strategy != "accept" || rule.Type == TypeRich {
return r.RichRules(rule, operation)
}
@@ -245,6 +288,7 @@ func (r *Firewall) parseRichRule(line string) (FireInfo, error) {
}
fireInfo := FireInfo{
Type: TypeRich,
Family: match[1],
Address: match[3],
Protocol: Protocol(match[5]),

View File

@@ -286,7 +286,7 @@ onMounted(() => {
<n-data-table
striped
remote
:scroll-x="1200"
:scroll-x="1400"
:loading="false"
:columns="columns"
:data="data"

View File

@@ -28,8 +28,8 @@ const webglAddon = new WebglAddon()
const current = ref(0)
const collapsed = ref(true)
const createModal = ref(false)
const updateModal = ref(false)
const create = ref(false)
const update = ref(false)
const updateId = ref(0)
const list = ref<MenuOption[]>([])
@@ -60,7 +60,7 @@ const fetchData = async () => {
type: 'primary',
size: 'small',
onClick: () => {
updateModal.value = true
update.value = true
updateId.value = item.id
}
},
@@ -114,7 +114,7 @@ const handleDelete = async (id: number) => {
term.value.dispose()
}
if (list.value.length === 0) {
createModal.value = true
create.value = true
}
}
}
@@ -172,10 +172,10 @@ const closeSession = () => {
try {
term.value.dispose()
sshWs?.close()
terminal.value!.innerHTML = ''
} catch {
/* empty */
}
terminal.value!.innerHTML = ''
}
const onResize = () => {
@@ -206,12 +206,12 @@ const onTermWheel = (event: WheelEvent) => {
}
}
watch(createModal, () => {
if (!createModal.value) fetchData()
watch(create, () => {
if (!create.value) fetchData()
})
watch(updateModal, () => {
if (!updateModal.value) {
watch(update, () => {
if (!update.value) {
fetchData()
updateId.value = 0
}
@@ -233,7 +233,7 @@ onUnmounted(() => {
<common-page show-footer>
<template #action>
<div flex items-center>
<n-button type="primary" @click="createModal = true">
<n-button type="primary" @click="create = true">
<TheIcon :size="18" icon="material-symbols:add" />
创建主机
</n-button>
@@ -265,8 +265,8 @@ onUnmounted(() => {
</n-layout-sider>
</n-layout>
</common-page>
<CreateModal v-model:show="createModal" />
<UpdateModal v-if="updateModal" v-model:show="updateModal" v-model:id="updateId" />
<create-modal v-if="create" v-model:show="create" />
<update-modal v-if="update" v-model:show="update" v-model:id="updateId" />
</template>
<style scoped lang="scss">

View File

@@ -8,13 +8,14 @@ import { NButton, NDataTable, NFlex, NInput, NPopconfirm, NSwitch, NTag } from '
import cron from '@/api/panel/cron'
import file from '@/api/panel/file'
import { formatDateTime, renderIcon } from '@/utils'
import CreateModal from '@/views/task/CreateModal.vue'
import type { CronTask } from '@/views/task/types'
import { CronNaive } from '@vue-js-cron/naive-ui'
const logPath = ref('')
const logModal = ref(false)
const editModal = ref(false)
const createModal = ref(false)
const create = ref(false)
const columns: any = [
{ type: 'selection', fixed: 'left' },
@@ -231,7 +232,7 @@ const saveTaskEdit = async () => {
})
}
watch(createModal, () => {
watch(create, () => {
onPageChange(pagination.page)
})
@@ -243,7 +244,7 @@ onMounted(() => {
<template>
<n-flex vertical>
<n-card flex-1 rounded-10>
<n-button type="primary" @click="createModal = true">创建计划任务</n-button>
<n-button type="primary" @click="create = true">创建计划任务</n-button>
</n-card>
<n-card flex-1 rounded-10>
<n-data-table
@@ -261,7 +262,6 @@ onMounted(() => {
/>
</n-card>
</n-flex>
<create-modal v-model:show="createModal" />
<realtime-log-modal v-model:show="logModal" :path="logPath" />
<n-modal
v-model:show="editModal"
@@ -294,4 +294,5 @@ onMounted(() => {
}"
/>
</n-modal>
<create-modal v-model:show="create" />
</template>