From af0ecce25b3e1b0cce4419b172a66604b54fca04 Mon Sep 17 00:00:00 2001 From: endymx <345793738@qq.com> Date: Sat, 15 Jun 2024 22:28:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=AB=AF=E5=8F=A3=E8=BD=AC=E5=8F=91?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=20(#5439)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/firewall.go | 23 ++ backend/app/dto/firewall.go | 11 + backend/app/model/firewall.go | 9 + backend/app/service/firewall.go | 84 ++++--- backend/init/app/app.go | 5 + backend/init/migration/migrate.go | 1 + backend/init/migration/migrations/v_1_10.go | 10 + backend/router/ro_host.go | 1 + backend/utils/firewall/client.go | 3 + backend/utils/firewall/client/firewalld.go | 51 +++- backend/utils/firewall/client/info.go | 24 +- backend/utils/firewall/client/iptables.go | 132 ++++++++++ backend/utils/firewall/client/ufw.go | 50 +++- frontend/src/api/interface/host.ts | 12 + frontend/src/api/modules/host.ts | 3 + frontend/src/lang/modules/en.ts | 7 + frontend/src/lang/modules/tw.ts | 6 + frontend/src/lang/modules/zh.ts | 8 + frontend/src/routers/modules/host.ts | 10 + frontend/src/utils/util.ts | 6 +- .../src/views/host/firewall/forward/index.vue | 226 ++++++++++++++++++ .../host/firewall/forward/operate/index.vue | 176 ++++++++++++++ frontend/src/views/host/firewall/index.vue | 4 + 23 files changed, 814 insertions(+), 48 deletions(-) create mode 100644 backend/utils/firewall/client/iptables.go create mode 100644 frontend/src/views/host/firewall/forward/index.vue create mode 100644 frontend/src/views/host/firewall/forward/operate/index.vue diff --git a/backend/app/api/v1/firewall.go b/backend/app/api/v1/firewall.go index ab59ceed2..b509e7064 100644 --- a/backend/app/api/v1/firewall.go +++ b/backend/app/api/v1/firewall.go @@ -94,6 +94,29 @@ func (b *BaseApi) OperatePortRule(c *gin.Context) { helper.SuccessWithData(c, nil) } +// OperateForwardRule +// @Tags Firewall +// @Summary Create group +// @Description 更新防火墙端口转发规则 +// @Accept json +// @Param request body dto.ForwardRuleOperate true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /hosts/firewall/forward [post] +// @x-panel-log {"bodyKeys":["source_port"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新端口转发规则 [source_port]","formatEN":"update port forward rules [source_port]"} +func (b *BaseApi) OperateForwardRule(c *gin.Context) { + var req dto.ForwardRuleOperate + if err := helper.CheckBindAndValidate(&req, c); err != nil { + return + } + + if err := firewallService.OperateForwardRule(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} + // @Tags Firewall // @Summary Create group // @Description 创建防火墙 IP 规则 diff --git a/backend/app/dto/firewall.go b/backend/app/dto/firewall.go index e9f8952fc..c3d3646e1 100644 --- a/backend/app/dto/firewall.go +++ b/backend/app/dto/firewall.go @@ -29,6 +29,17 @@ type PortRuleOperate struct { Description string `json:"description"` } +type ForwardRuleOperate struct { + Rules []struct { + Operation string `json:"operation" validate:"required,oneof=add remove"` + Num string `json:"num"` + Protocol string `json:"protocol" validate:"required,oneof=tcp udp tcp/udp"` + Port string `json:"port" validate:"required"` + TargetIP string `json:"targetIP"` + TargetPort string `json:"targetPort" validate:"required"` + } `json:"rules"` +} + type UpdateFirewallDescription struct { Type string `json:"type"` Address string `json:"address"` diff --git a/backend/app/model/firewall.go b/backend/app/model/firewall.go index ed89be900..d4979a05d 100644 --- a/backend/app/model/firewall.go +++ b/backend/app/model/firewall.go @@ -10,3 +10,12 @@ type Firewall struct { Strategy string `gorm:"type:varchar(64);not null" json:"strategy"` Description string `gorm:"type:varchar(64);not null" json:"description"` } + +type Forward struct { + BaseModel + + Protocol string `gorm:"type:varchar(64);not null" json:"protocol"` + Port string `gorm:"type:varchar(64);not null" json:"port"` + TargetIP string `gorm:"type:varchar(64);not null" json:"targetIP"` + TargetPort string `gorm:"type:varchar(64);not null" json:"targetPort"` +} diff --git a/backend/app/service/firewall.go b/backend/app/service/firewall.go index 84aa829f9..fe6f948c5 100644 --- a/backend/app/service/firewall.go +++ b/backend/app/service/firewall.go @@ -3,6 +3,7 @@ package service import ( "fmt" "os" + "sort" "strconv" "strings" "sync" @@ -28,6 +29,7 @@ type IFirewallService interface { SearchWithPage(search dto.RuleSearch) (int64, interface{}, error) OperateFirewall(operation string) error OperatePortRule(req dto.PortRuleOperate, reload bool) error + OperateForwardRule(req dto.ForwardRuleOperate) error OperateAddressRule(req dto.AddrRuleOperate, reload bool) error UpdatePortRule(req dto.PortRuleUpdate) error UpdateAddrRule(req dto.AddrRuleUpdate) error @@ -78,42 +80,36 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{} if err != nil { return 0, nil, err } - if req.Type == "port" { - ports, err := client.ListPort() - if err != nil { - return 0, nil, err - } - if len(req.Info) != 0 { - for _, port := range ports { - if strings.Contains(port.Port, req.Info) { - datas = append(datas, port) - } - } - } else { - datas = ports - } - } else { - addrs, err := client.ListAddress() - if err != nil { - return 0, nil, err - } - if len(req.Info) != 0 { - for _, addr := range addrs { - if strings.Contains(addr.Address, req.Info) { - datas = append(datas, addr) - } - } - } else { - datas = addrs - } + + var rules []fireClient.FireInfo + switch req.Type { + case "port": + rules, err = client.ListPort() + case "forward": + rules, err = client.ListForward() + case "address": + rules, err = client.ListAddress() + } + if err != nil { + return 0, nil, err } + if len(req.Info) != 0 { + for _, addr := range rules { + if strings.Contains(addr.Address, req.Info) { + datas = append(datas, addr) + } + } + } else { + datas = rules + } if req.Type == "port" { apps := u.loadPortByApp() for i := 0; i < len(datas); i++ { datas[i].UsedStatus = checkPortUsed(datas[i].Port, datas[i].Protocol, apps) } } + var datasFilterStatus []fireClient.FireInfo if len(req.Status) != 0 { for _, data := range datas { @@ -127,6 +123,7 @@ func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{} } else { datasFilterStatus = datas } + var datasFilterStrategy []fireClient.FireInfo if len(req.Strategy) != 0 { for _, data := range datasFilterStatus { @@ -300,6 +297,37 @@ func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate, reload bool) return nil } +func (u *FirewallService) OperateForwardRule(req dto.ForwardRuleOperate) error { + client, err := firewall.NewFirewallClient() + if err != nil { + return err + } + + sort.SliceStable(req.Rules, func(i, j int) bool { + n1, _ := strconv.Atoi(req.Rules[i].Num) + n2, _ := strconv.Atoi(req.Rules[j].Num) + return n1 > n2 + }) + + for _, r := range req.Rules { + for _, p := range strings.Split(r.Protocol, "/") { + if r.TargetIP == "" { + r.TargetIP = "127.0.0.1" + } + if err = client.PortForward(fireClient.Forward{ + Num: r.Num, + Protocol: p, + Port: r.Port, + TargetIP: r.TargetIP, + TargetPort: r.TargetPort, + }, r.Operation); err != nil { + return err + } + } + } + return nil +} + func (u *FirewallService) OperateAddressRule(req dto.AddrRuleOperate, reload bool) error { client, err := firewall.NewFirewallClient() if err != nil { diff --git a/backend/init/app/app.go b/backend/init/app/app.go index 45fa7f2bc..422657961 100644 --- a/backend/init/app/app.go +++ b/backend/init/app/app.go @@ -2,6 +2,7 @@ package app import ( "github.com/1Panel-dev/1Panel/backend/utils/docker" + "github.com/1Panel-dev/1Panel/backend/utils/firewall" "path" "github.com/1Panel-dev/1Panel/backend/constant" @@ -31,6 +32,10 @@ func Init() { } _ = docker.CreateDefaultDockerNetwork() + + if f, err := firewall.NewFirewallClient(); err == nil { + _ = f.EnableForward() + } } func createDir(fileOp files.FileOp, dirPath string) { diff --git a/backend/init/migration/migrate.go b/backend/init/migration/migrate.go index 407634f13..5f40b8038 100644 --- a/backend/init/migration/migrate.go +++ b/backend/init/migration/migrate.go @@ -89,6 +89,7 @@ func Init() { migrations.AddFtp, migrations.AddProxy, migrations.AddCronJobColumn, + migrations.AddForward, }) if err := m.Migrate(); err != nil { global.LOG.Error(err) diff --git a/backend/init/migration/migrations/v_1_10.go b/backend/init/migration/migrations/v_1_10.go index 0d32daea0..7e72e15d4 100644 --- a/backend/init/migration/migrations/v_1_10.go +++ b/backend/init/migration/migrations/v_1_10.go @@ -239,6 +239,16 @@ var AddProxy = &gormigrate.Migration{ }, } +var AddForward = &gormigrate.Migration{ + ID: "202400611-add-forward", + Migrate: func(tx *gorm.DB) error { + if err := tx.AutoMigrate(&model.Forward{}); err != nil { + return err + } + return nil + }, +} + var AddCronJobColumn = &gormigrate.Migration{ ID: "20240524-add-cronjob-command", Migrate: func(tx *gorm.DB) error { diff --git a/backend/router/ro_host.go b/backend/router/ro_host.go index 8a589ca86..c35abfd62 100644 --- a/backend/router/ro_host.go +++ b/backend/router/ro_host.go @@ -29,6 +29,7 @@ func (s *HostRouter) InitRouter(Router *gin.RouterGroup) { hostRouter.POST("/firewall/search", baseApi.SearchFirewallRule) hostRouter.POST("/firewall/operate", baseApi.OperateFirewall) hostRouter.POST("/firewall/port", baseApi.OperatePortRule) + hostRouter.POST("/firewall/forward", baseApi.OperateForwardRule) hostRouter.POST("/firewall/ip", baseApi.OperateIPRule) hostRouter.POST("/firewall/batch", baseApi.BatchOperateRule) hostRouter.POST("/firewall/update/port", baseApi.UpdatePortRule) diff --git a/backend/utils/firewall/client.go b/backend/utils/firewall/client.go index f2512bcd6..de88fca35 100644 --- a/backend/utils/firewall/client.go +++ b/backend/utils/firewall/client.go @@ -18,11 +18,14 @@ type FirewallClient interface { Version() (string, error) ListPort() ([]client.FireInfo, error) + ListForward() ([]client.FireInfo, error) ListAddress() ([]client.FireInfo, error) Port(port client.FireInfo, operation string) error RichRules(rule client.FireInfo, operation string) error PortForward(info client.Forward, operation string) error + + EnableForward() error } func NewFirewallClient() (FirewallClient, error) { diff --git a/backend/utils/firewall/client/firewalld.go b/backend/utils/firewall/client/firewalld.go index 4c9a2a723..4cc704453 100644 --- a/backend/utils/firewall/client/firewalld.go +++ b/backend/utils/firewall/client/firewalld.go @@ -2,6 +2,7 @@ package client import ( "fmt" + "regexp" "strings" "sync" @@ -10,6 +11,8 @@ import ( "github.com/1Panel-dev/1Panel/backend/utils/cmd" ) +var ForwardListRegex = regexp.MustCompile(`^port=(\d{1,5}):proto=(.+?):toport=(\d{1,5}):toaddr=(.*)$`) + type Firewall struct{} func NewFirewalld() (*Firewall, error) { @@ -115,6 +118,29 @@ func (f *Firewall) ListPort() ([]FireInfo, error) { return datas, nil } +func (f *Firewall) ListForward() ([]FireInfo, error) { + stdout, err := cmd.Exec("firewall-cmd --zone=public --list-forward-ports") + if err != nil { + return nil, err + } + var datas []FireInfo + for _, line := range strings.Split(stdout, "\n") { + line = strings.TrimFunc(line, func(r rune) bool { + return r <= 32 + }) + if ForwardListRegex.MatchString(line) { + match := ForwardListRegex.FindStringSubmatch(line) + datas = append(datas, FireInfo{ + Port: match[1], + Protocol: match[2], + TargetIP: match[4], + TargetPort: match[3], + }) + } + } + return datas, nil +} + func (f *Firewall) ListAddress() ([]FireInfo, error) { stdout, err := cmd.Exec("firewall-cmd --zone=public --list-rich-rules") if err != nil { @@ -175,15 +201,18 @@ func (f *Firewall) RichRules(rule FireInfo, operation string) error { } func (f *Firewall) PortForward(info Forward, operation string) error { - ruleStr := fmt.Sprintf("firewall-cmd --%s-forward-port=port=%s:proto=%s:toport=%s --permanent", operation, info.Port, info.Protocol, info.Target) - if len(info.Address) != 0 { - ruleStr = fmt.Sprintf("firewall-cmd --%s-forward-port=port=%s:proto=%s:toaddr=%s:toport=%s --permanent", operation, info.Port, info.Protocol, info.Address, info.Target) + ruleStr := fmt.Sprintf("firewall-cmd --zone=public --%s-forward-port=port=%s:proto=%s:toport=%s --permanent", operation, info.Port, info.Protocol, info.TargetPort) + if info.TargetIP != "" && info.TargetIP != "127.0.0.1" && info.TargetIP != "localhost" { + ruleStr = fmt.Sprintf("firewall-cmd --zone=public --%s-forward-port=port=%s:proto=%s:toaddr=%s:toport=%s --permanent", operation, info.Port, info.Protocol, info.TargetIP, info.TargetPort) } stdout, err := cmd.Exec(ruleStr) if err != nil { return fmt.Errorf("%s port forward failed, err: %s", operation, stdout) } + if err = f.Reload(); err != nil { + return err + } return nil } @@ -208,3 +237,19 @@ func (f *Firewall) loadInfo(line string) FireInfo { } return itemRule } + +func (f *Firewall) EnableForward() error { + stdout, err := cmd.Exec("firewall-cmd --zone=public --query-masquerade") + if err != nil { + if strings.HasSuffix(strings.TrimSpace(stdout), "no") { + stdout, err = cmd.Exec("firewall-cmd --zone=public --add-masquerade --permanent") + if err != nil { + return fmt.Errorf("%s: %s", err, stdout) + } + return f.Reload() + } + return fmt.Errorf("%s: %s", err, stdout) + } + + return nil +} diff --git a/backend/utils/firewall/client/info.go b/backend/utils/firewall/client/info.go index 3a4723c1d..3503c25ed 100644 --- a/backend/utils/firewall/client/info.go +++ b/backend/utils/firewall/client/info.go @@ -7,13 +7,29 @@ type FireInfo struct { Protocol string `json:"protocol"` // tcp udp tcp/udp Strategy string `json:"strategy"` // accept drop + Num string `json:"num"` + TargetIP string `json:"targetIP"` + TargetPort string `json:"targetPort"` + UsedStatus string `json:"usedStatus"` Description string `json:"description"` } type Forward struct { - Protocol string `json:"protocol"` - Address string `json:"address"` - Port string `json:"port"` - Target string `json:"target"` + Num string `json:"num"` + Protocol string `json:"protocol"` + Port string `json:"port"` + TargetIP string `json:"targetIP"` + TargetPort string `json:"targetPort"` +} + +type IptablesNatInfo struct { + Num string `json:"num"` + Target string `json:"target"` + Protocol string `json:"protocol"` + Opt string `json:"opt"` + Source string `json:"source"` + Destination string `json:"destination"` + SrcPort string `json:"srcPort"` + DestPort string `json:"destPort"` } diff --git a/backend/utils/firewall/client/iptables.go b/backend/utils/firewall/client/iptables.go new file mode 100644 index 000000000..5ad5d746f --- /dev/null +++ b/backend/utils/firewall/client/iptables.go @@ -0,0 +1,132 @@ +package client + +import ( + "fmt" + "github.com/1Panel-dev/1Panel/backend/app/model" + "github.com/1Panel-dev/1Panel/backend/global" + "github.com/1Panel-dev/1Panel/backend/utils/cmd" + "github.com/pkg/errors" + "regexp" + "strings" +) + +var NatListRegex = regexp.MustCompile(`^(\d+)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?)\s+(.+?) .+?:(\d{1,5}(?::\d+)?).+?[ :](.+-.+|(?:.+:)?\d{1,5}(?:-\d{1,5})?)$`) + +type Iptables struct { + CmdStr string +} + +func NewIptables() (*Iptables, error) { + iptables := new(Iptables) + if cmd.HasNoPasswordSudo() { + iptables.CmdStr = "sudo" + } + + return iptables, nil +} + +func (iptables *Iptables) Check() error { + stdout, err := cmd.Exec("cat /proc/sys/net/ipv4/ip_forward") + if err != nil { + return err + } + if stdout == "0" { + return fmt.Errorf("disable") + } + + return nil +} + +func (iptables *Iptables) NatList() ([]IptablesNatInfo, error) { + stdout, err := cmd.Execf("%s iptables -t nat -nL PREROUTING --line", iptables.CmdStr) + if err != nil { + return nil, err + } + + 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[9], ":") { + match[9] = fmt.Sprintf(":%s", match[9]) + } + forwardList = append(forwardList, IptablesNatInfo{ + Num: match[1], + Target: match[2], + Protocol: match[7], + Opt: match[4], + Source: match[5], + Destination: match[6], + SrcPort: match[8], + DestPort: match[9], + }) + } + } + + return forwardList, nil +} + +func (iptables *Iptables) NatAdd(protocol, src, destIp, destPort string, save bool) error { + rule := fmt.Sprintf("%s iptables -t nat -A PREROUTING -p %s --dport %s -j REDIRECT --to-port %s", iptables.CmdStr, protocol, src, destPort) + if destIp != "" && destIp != "127.0.0.1" && destIp != "localhost" { + rule = fmt.Sprintf("%s iptables -t nat -A PREROUTING -p %s --dport %s -j DNAT --to-destination %s:%s", iptables.CmdStr, protocol, src, destIp, destPort) + } + stdout, err := cmd.Exec(rule) + if err != nil { + return err + } + if stdout != "" { + return errors.New(stdout) + } + + if save { + return global.DB.Save(&model.Forward{ + Protocol: protocol, + Port: src, + TargetIP: destIp, + TargetPort: destPort, + }).Error + } + return nil +} + +func (iptables *Iptables) NatRemove(num string, protocol, src, destIp, destPort string) error { + stdout, err := cmd.Execf("%s iptables -t nat -D PREROUTING %s", iptables.CmdStr, num) + if err != nil { + return err + } + if stdout != "" { + return fmt.Errorf(stdout) + } + + global.DB.Where( + "protocol = ? AND port = ? AND target_ip = ? AND target_port = ?", + protocol, + src, + destIp, + destPort, + ).Delete(&model.Forward{}) + return nil +} + +func (iptables *Iptables) Reload() error { + stdout, err := cmd.Execf("%s iptables -t nat -F && %s iptables -t nat -X", iptables.CmdStr, iptables.CmdStr) + if err != nil { + return err + } + if stdout != "" { + return fmt.Errorf(stdout) + } + + var rules []model.Forward + global.DB.Find(&rules) + for _, forward := range rules { + if err := iptables.NatAdd(forward.Protocol, forward.Port, forward.TargetIP, forward.TargetPort, false); err != nil { + return err + } + } + return nil +} diff --git a/backend/utils/firewall/client/ufw.go b/backend/utils/firewall/client/ufw.go index f7bd48897..d5c7dc3e8 100644 --- a/backend/utils/firewall/client/ufw.go +++ b/backend/utils/firewall/client/ufw.go @@ -103,6 +103,30 @@ func (f *Ufw) ListPort() ([]FireInfo, error) { return datas, nil } +func (f *Ufw) ListForward() ([]FireInfo, error) { + iptables, err := NewIptables() + if err != nil { + return nil, err + } + rules, err := iptables.NatList() + if err != nil { + return nil, err + } + + var list []FireInfo + for _, rule := range rules { + dest := strings.SplitN(rule.DestPort, ":", 2) + list = append(list, FireInfo{ + Num: rule.Num, + Protocol: rule.Protocol, + Port: rule.SrcPort, + TargetIP: dest[0], + TargetPort: dest[1], + }) + } + return list, nil +} + func (f *Ufw) ListAddress() ([]FireInfo, error) { stdout, err := cmd.Execf("%s status verbose", f.CmdStr) if err != nil { @@ -206,17 +230,18 @@ func (f *Ufw) RichRules(rule FireInfo, operation string) error { } func (f *Ufw) PortForward(info Forward, operation string) error { - ruleStr := fmt.Sprintf("firewall-cmd --%s-forward-port=port=%s:proto=%s:toport=%s --permanent", operation, info.Port, info.Protocol, info.Target) - if len(info.Address) != 0 { - ruleStr = fmt.Sprintf("firewall-cmd --%s-forward-port=port=%s:proto=%s:toaddr=%s:toport=%s --permanent", operation, info.Port, info.Protocol, info.Address, info.Target) + iptables, err := NewIptables() + if err != nil { + return err } - stdout, err := cmd.Exec(ruleStr) - if err != nil { - return fmt.Errorf("%s port forward failed, err: %s", operation, stdout) + if operation == "add" { + err = iptables.NatAdd(info.Protocol, info.Port, info.TargetIP, info.TargetPort, true) + } else { + err = iptables.NatRemove(info.Num, info.Protocol, info.Port, info.TargetIP, info.TargetPort) } - if err := f.Reload(); err != nil { - return err + if err != nil { + return fmt.Errorf("%s port forward failed, err: %s", operation, err) } return nil } @@ -258,3 +283,12 @@ func (f *Ufw) loadInfo(line string, fireType string) FireInfo { return itemInfo } + +func (f *Ufw) EnableForward() error { + iptables, err := NewIptables() + if err != nil { + return err + } + + return iptables.Reload() +} diff --git a/frontend/src/api/interface/host.ts b/frontend/src/api/interface/host.ts index d03b87c6e..7cced8c08 100644 --- a/frontend/src/api/interface/host.ts +++ b/frontend/src/api/interface/host.ts @@ -74,12 +74,17 @@ export namespace Host { export interface RuleInfo extends ReqPage { family: string; address: string; + destination: string; port: string; + srcPort: string; + destPort: string; protocol: string; strategy: string; usedStatus: string; description: string; + + [key: string]: any; } export interface UpdateDescription { address: string; @@ -97,6 +102,13 @@ export namespace Host { strategy: string; description: string; } + export interface RuleForward { + operation: string; + protocol: string; + port: string; + targetIP: string; + targetPort: string; + } export interface RuleIP { operation: string; address: string; diff --git a/frontend/src/api/modules/host.ts b/frontend/src/api/modules/host.ts index 4eb6492c8..172cf55e9 100644 --- a/frontend/src/api/modules/host.ts +++ b/frontend/src/api/modules/host.ts @@ -98,6 +98,9 @@ export const operateFire = (operation: string) => { export const operatePortRule = (params: Host.RulePort) => { return http.post(`/hosts/firewall/port`, params, TimeoutEnum.T_40S); }; +export const operateForwardRule = (params: { rules: Host.RuleForward[] }) => { + return http.post(`/hosts/firewall/forward`, params, TimeoutEnum.T_40S); +}; export const operateIPRule = (params: Host.RuleIP) => { return http.post(`/hosts/firewall/ip`, params, TimeoutEnum.T_40S); }; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index fe4e6b702..49cefb475 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -1,4 +1,5 @@ import fit2cloudEnLocale from 'fit2cloud-ui-plus/src/locale/lang/en'; + let xpackEnLocale = {}; const xpackModules = import.meta.glob('../../xpack/lang/en.ts', { eager: true }); if (xpackModules['../../xpack/lang/en.ts']) { @@ -2204,8 +2205,14 @@ const message = { addressHelper2: 'For multiple IPs or IP ranges, separate with commas: 172.16.10.11, 172.16.0.0/24', allIP: 'All IP', portRule: 'Port rule', + forwardRule: 'Forwarding', ipRule: 'IP rule', userAgent: 'User-Agent filter', + sourcePort: 'Source Port', + targetIP: 'Destination IP', + targetPort: 'Destination Port', + forwardHelper1: 'In the case of local port forwarding, the destination IP is: 127.0.0.1', + forwardHelper2: 'If the destination IP is not filled in, it will be forwarded to the local port by default', }, runtime: { runtime: 'Runtime', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index 54926ebf3..cacec876f 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -2048,8 +2048,14 @@ const message = { addressHelper2: '多個 IP 或 IP 段 請用 "," 隔開:172.16.10.11,172.16.0.0/24', allIP: '所有 IP', portRule: '端口規則', + forwardRule: '端口轉發', ipRule: 'IP 規則', userAgent: 'User-Agent 過濾', + sourcePort: '來源端口', + targetIP: '目標 IP', + targetPort: '目標端口', + forwardHelper1: '如果是本機端口轉發,目標 IP 為:127.0.0.1', + forwardHelper2: '如果目標 IP 不填寫,默認為本機端口轉發', }, runtime: { runtime: '運行環境', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index e217a6596..f5f8571f9 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -92,6 +92,7 @@ const message = { user: '用户', title: '标题', port: '端口', + forward: '转发', protocol: '协议', tableSetting: '列表设置', refreshRate: '刷新频率', @@ -2049,8 +2050,15 @@ const message = { addressHelper2: '多个 IP 或 IP 段 请用 "," 隔开:172.16.10.11,172.16.0.0/24', allIP: '所有 IP', portRule: '端口规则', + forwardRule: '端口转发', ipRule: 'IP 规则', userAgent: 'User-Agent 过滤', + destination: '目的地', + sourcePort: '源端口', + targetIP: '目标 IP', + targetPort: '目标端口', + forwardHelper1: '如果是本机端口转发,目标IP为:127.0.0.1', + forwardHelper2: '如果目标IP不填写,则默认为本机端口转发', }, runtime: { runtime: '运行环境', diff --git a/frontend/src/routers/modules/host.ts b/frontend/src/routers/modules/host.ts index cce29f457..08dd04236 100644 --- a/frontend/src/routers/modules/host.ts +++ b/frontend/src/routers/modules/host.ts @@ -60,6 +60,16 @@ const hostRouter = { requiresAuth: false, }, }, + { + path: '/hosts/firewall/forward', + name: 'FirewallForward', + component: () => import('@/views/host/firewall/forward/index.vue'), + hidden: true, + meta: { + activeMenu: '/hosts/firewall/port', + requiresAuth: false, + }, + }, { path: '/hosts/firewall/ip', name: 'FirewallIP', diff --git a/frontend/src/utils/util.ts b/frontend/src/utils/util.ts index 50f809f70..21bd27583 100644 --- a/frontend/src/utils/util.ts +++ b/frontend/src/utils/util.ts @@ -327,11 +327,7 @@ export function checkPort(value: string): boolean { return true; } const reg = /^([1-9](\d{0,3}))$|^([1-5]\d{4})$|^(6[0-4]\d{3})$|^(65[0-4]\d{2})$|^(655[0-2]\d)$|^(6553[0-5])$/; - if (!reg.test(value) && value !== '') { - return true; - } else { - return false; - } + return !reg.test(value) && value !== ''; } export function getProvider(provider: string): string { diff --git a/frontend/src/views/host/firewall/forward/index.vue b/frontend/src/views/host/firewall/forward/index.vue new file mode 100644 index 000000000..69b1443e0 --- /dev/null +++ b/frontend/src/views/host/firewall/forward/index.vue @@ -0,0 +1,226 @@ + + + + + diff --git a/frontend/src/views/host/firewall/forward/operate/index.vue b/frontend/src/views/host/firewall/forward/operate/index.vue new file mode 100644 index 000000000..29b932581 --- /dev/null +++ b/frontend/src/views/host/firewall/forward/operate/index.vue @@ -0,0 +1,176 @@ + + + diff --git a/frontend/src/views/host/firewall/index.vue b/frontend/src/views/host/firewall/index.vue index 3d24fdef0..0c7d314c8 100644 --- a/frontend/src/views/host/firewall/index.vue +++ b/frontend/src/views/host/firewall/index.vue @@ -15,6 +15,10 @@ const buttons = [ label: i18n.global.t('firewall.portRule'), path: '/hosts/firewall/port', }, + { + label: i18n.global.t('firewall.forwardRule'), + path: '/hosts/firewall/forward', + }, { label: i18n.global.t('firewall.ipRule'), path: '/hosts/firewall/ip',