mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-31 22:18:07 +08:00
feat: 完成前端端口规则设置功能
This commit is contained in:
parent
a2fcdabb7b
commit
d5f446d7cf
@ -29,6 +29,7 @@ var (
|
|||||||
hostService = service.ServiceGroupApp.HostService
|
hostService = service.ServiceGroupApp.HostService
|
||||||
groupService = service.ServiceGroupApp.GroupService
|
groupService = service.ServiceGroupApp.GroupService
|
||||||
fileService = service.ServiceGroupApp.FileService
|
fileService = service.ServiceGroupApp.FileService
|
||||||
|
firewallService = service.NewIFirewallService()
|
||||||
|
|
||||||
settingService = service.ServiceGroupApp.SettingService
|
settingService = service.ServiceGroupApp.SettingService
|
||||||
backupService = service.ServiceGroupApp.BackupService
|
backupService = service.ServiceGroupApp.BackupService
|
||||||
|
101
backend/app/api/v1/firewall.go
Normal file
101
backend/app/api/v1/firewall.go
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
package v1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Page firewall rules
|
||||||
|
// @Description 获取防火墙规则列表分页
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.SearchWithPage true "request"
|
||||||
|
// @Success 200 {object} dto.PageResult
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/search [post]
|
||||||
|
func (b *BaseApi) SearchFirewallRule(c *gin.Context) {
|
||||||
|
var req dto.RuleSearch
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
total, list, err := firewallService.SearchWithPage(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, dto.PageResult{
|
||||||
|
Items: list,
|
||||||
|
Total: total,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Create group
|
||||||
|
// @Description 创建防火墙端口规则
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.PortRuleOperate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/port [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["port","strategy"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"添加端口规则 {[strategy] [port]}","formatEN":"create port rules {[strategy][port]}"}
|
||||||
|
func (b *BaseApi) OperatePortRule(c *gin.Context) {
|
||||||
|
var req dto.PortRuleOperate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if req.Protocol == "tcp/udp" {
|
||||||
|
req.Protocol = "tcp"
|
||||||
|
if err := firewallService.OperatePortRule(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Protocol = "udp"
|
||||||
|
if err := firewallService.OperatePortRule(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
if err := firewallService.OperatePortRule(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags Firewall
|
||||||
|
// @Summary Create group
|
||||||
|
// @Description 创建防火墙 IP 规则
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body dto.AddressCreate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /hosts/firewall/ip [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["strategy","address"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"添加 ip 规则 {[strategy] [address]}","formatEN":"create address rules {[strategy][address]}"}
|
||||||
|
func (b *BaseApi) OperateIPRule(c *gin.Context) {
|
||||||
|
var req dto.AddrRuleOperate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := global.VALID.Struct(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := firewallService.OperateAddressRule(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
20
backend/app/dto/firewall.go
Normal file
20
backend/app/dto/firewall.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package dto
|
||||||
|
|
||||||
|
type RuleSearch struct {
|
||||||
|
PageInfo
|
||||||
|
Type string `json:"type" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PortRuleOperate struct {
|
||||||
|
Operation string `json:"operation" validate:"required,oneof=add remove"`
|
||||||
|
Address string `json:"address"`
|
||||||
|
Port string `json:"port" validate:"required"`
|
||||||
|
Protocol string `json:"protocol" validate:"required,oneof=tcp udp tcp/upd"`
|
||||||
|
Strategy string `json:"strategy" validate:"required,oneof=accept drop"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AddrRuleOperate struct {
|
||||||
|
Operation string `json:"operation" validate:"required,oneof=add remove"`
|
||||||
|
Address string `json:"address" validate:"required"`
|
||||||
|
Strategy string `json:"strategy" validate:"required,oneof=accept drop"`
|
||||||
|
}
|
@ -24,6 +24,7 @@ type ServiceGroup struct {
|
|||||||
GroupService
|
GroupService
|
||||||
CommandService
|
CommandService
|
||||||
FileService
|
FileService
|
||||||
|
FirewallService
|
||||||
|
|
||||||
SettingService
|
SettingService
|
||||||
BackupService
|
BackupService
|
||||||
|
85
backend/app/service/firewall.go
Normal file
85
backend/app/service/firewall.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/firewall"
|
||||||
|
fireClient "github.com/1Panel-dev/1Panel/backend/utils/firewall/client"
|
||||||
|
"github.com/jinzhu/copier"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FirewallService struct{}
|
||||||
|
|
||||||
|
type IFirewallService interface {
|
||||||
|
SearchWithPage(search dto.RuleSearch) (int64, interface{}, error)
|
||||||
|
OperatePortRule(req dto.PortRuleOperate) error
|
||||||
|
OperateAddressRule(req dto.AddrRuleOperate) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIFirewallService() IFirewallService {
|
||||||
|
return &FirewallService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) SearchWithPage(req dto.RuleSearch) (int64, interface{}, error) {
|
||||||
|
var (
|
||||||
|
datas []fireClient.FireInfo
|
||||||
|
backDatas []fireClient.FireInfo
|
||||||
|
)
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
if req.Type == "port" {
|
||||||
|
ports, err := client.ListPort()
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
datas = ports
|
||||||
|
} else {
|
||||||
|
address, err := client.ListAddress()
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
datas = address
|
||||||
|
}
|
||||||
|
total, start, end := len(datas), (req.Page-1)*req.PageSize, req.Page*req.PageSize
|
||||||
|
if start > total {
|
||||||
|
backDatas = make([]fireClient.FireInfo, 0)
|
||||||
|
} else {
|
||||||
|
if end >= total {
|
||||||
|
end = total
|
||||||
|
}
|
||||||
|
backDatas = datas[start:end]
|
||||||
|
}
|
||||||
|
|
||||||
|
return int64(total), backDatas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) OperatePortRule(req dto.PortRuleOperate) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var fireInfo fireClient.FireInfo
|
||||||
|
if err := copier.Copy(&fireInfo, &req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(fireInfo.Address) != 0 || fireInfo.Strategy == "drop" {
|
||||||
|
return client.RichRules(fireInfo, req.Operation)
|
||||||
|
}
|
||||||
|
return client.Port(fireInfo, req.Operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *FirewallService) OperateAddressRule(req dto.AddrRuleOperate) error {
|
||||||
|
client, err := firewall.NewFirewallClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var fireInfo fireClient.FireInfo
|
||||||
|
if err := copier.Copy(&fireInfo, &req); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return client.RichRules(fireInfo, req.Operation)
|
||||||
|
}
|
@ -26,6 +26,10 @@ func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) {
|
|||||||
hostRouter.POST("/test/byid/:id", baseApi.TestByID)
|
hostRouter.POST("/test/byid/:id", baseApi.TestByID)
|
||||||
hostRouter.GET(":id", baseApi.GetHostInfo)
|
hostRouter.GET(":id", baseApi.GetHostInfo)
|
||||||
|
|
||||||
|
hostRouter.POST("/firewall/search", baseApi.SearchFirewallRule)
|
||||||
|
hostRouter.POST("/firewall/port", baseApi.OperatePortRule)
|
||||||
|
hostRouter.POST("/firewall/ip", baseApi.OperateIPRule)
|
||||||
|
|
||||||
hostRouter.GET("/command", baseApi.ListCommand)
|
hostRouter.GET("/command", baseApi.ListCommand)
|
||||||
hostRouter.POST("/command", baseApi.CreateCommand)
|
hostRouter.POST("/command", baseApi.CreateCommand)
|
||||||
hostRouter.POST("/command/del", baseApi.DeleteCommand)
|
hostRouter.POST("/command/del", baseApi.DeleteCommand)
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package firewall
|
package firewall
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/firewall/client"
|
"github.com/1Panel-dev/1Panel/backend/utils/firewall/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -13,7 +10,7 @@ type FirewallClient interface {
|
|||||||
Reload() error
|
Reload() error
|
||||||
Status() (string, error)
|
Status() (string, error)
|
||||||
ListPort() ([]client.FireInfo, error)
|
ListPort() ([]client.FireInfo, error)
|
||||||
ListRichRules() ([]client.FireInfo, error)
|
ListAddress() ([]client.FireInfo, error)
|
||||||
|
|
||||||
Port(port client.FireInfo, operation string) error
|
Port(port client.FireInfo, operation string) error
|
||||||
RichRules(rule client.FireInfo, operation string) error
|
RichRules(rule client.FireInfo, operation string) error
|
||||||
@ -21,11 +18,11 @@ type FirewallClient interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewFirewallClient() (FirewallClient, error) {
|
func NewFirewallClient() (FirewallClient, error) {
|
||||||
if _, err := os.Stat("/usr/sbin/firewalld"); err == nil {
|
// if _, err := os.Stat("/usr/sbin/firewalld"); err == nil {
|
||||||
return client.NewFirewalld()
|
return client.NewFirewalld()
|
||||||
}
|
// }
|
||||||
// if _, err := os.Stat("/usr/sbin/ufw"); err == nil {
|
// if _, err := os.Stat("/usr/sbin/ufw"); err == nil {
|
||||||
// return client.NewUfw()
|
// return client.NewUfw()
|
||||||
// }
|
// }
|
||||||
return nil, errors.New("no such type")
|
// return nil, errors.New("no such type")
|
||||||
}
|
}
|
||||||
|
@ -4,17 +4,25 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
"github.com/1Panel-dev/1Panel/backend/utils/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Firewall struct{}
|
type Firewall struct {
|
||||||
|
Client ssh.ConnInfo
|
||||||
|
}
|
||||||
|
|
||||||
func NewFirewalld() (*Firewall, error) {
|
func NewFirewalld() (*Firewall, error) {
|
||||||
return &Firewall{}, nil
|
ConnInfo := ssh.ConnInfo{
|
||||||
|
Addr: "172.16.10.143",
|
||||||
|
User: "root",
|
||||||
|
AuthMode: "password",
|
||||||
|
Port: 22,
|
||||||
|
}
|
||||||
|
return &Firewall{Client: ConnInfo}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Firewall) Status() (string, error) {
|
func (f *Firewall) Status() (string, error) {
|
||||||
stdout, err := cmd.Exec("firewall-cmd --state")
|
stdout, err := f.Client.Run("firewall-cmd --state")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("load the firewall status failed, err: %s", stdout)
|
return "", fmt.Errorf("load the firewall status failed, err: %s", stdout)
|
||||||
}
|
}
|
||||||
@ -22,7 +30,7 @@ func (f *Firewall) Status() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Firewall) Start() error {
|
func (f *Firewall) Start() error {
|
||||||
stdout, err := cmd.Exec("systemctl start firewalld")
|
stdout, err := f.Client.Run("systemctl start firewalld")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("enable the firewall failed, err: %s", stdout)
|
return fmt.Errorf("enable the firewall failed, err: %s", stdout)
|
||||||
}
|
}
|
||||||
@ -30,7 +38,7 @@ func (f *Firewall) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Firewall) Stop() error {
|
func (f *Firewall) Stop() error {
|
||||||
stdout, err := cmd.Exec("systemctl stop firewalld")
|
stdout, err := f.Client.Run("systemctl stop firewalld")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("stop the firewall failed, err: %s", stdout)
|
return fmt.Errorf("stop the firewall failed, err: %s", stdout)
|
||||||
}
|
}
|
||||||
@ -38,7 +46,7 @@ func (f *Firewall) Stop() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Firewall) Reload() error {
|
func (f *Firewall) Reload() error {
|
||||||
stdout, err := cmd.Exec("firewall-cmd --reload")
|
stdout, err := f.Client.Run("firewall-cmd --reload")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reload firewall failed, err: %s", stdout)
|
return fmt.Errorf("reload firewall failed, err: %s", stdout)
|
||||||
}
|
}
|
||||||
@ -46,7 +54,7 @@ func (f *Firewall) Reload() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Firewall) ListPort() ([]FireInfo, error) {
|
func (f *Firewall) ListPort() ([]FireInfo, error) {
|
||||||
stdout, err := cmd.Exec("firewall-cmd --zone=public --list-ports")
|
stdout, err := f.Client.Run("firewall-cmd --zone=public --list-ports")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -58,13 +66,29 @@ func (f *Firewall) ListPort() ([]FireInfo, error) {
|
|||||||
itemPort.Port = strings.Split(port, "/")[0]
|
itemPort.Port = strings.Split(port, "/")[0]
|
||||||
itemPort.Protocol = strings.Split(port, "/")[1]
|
itemPort.Protocol = strings.Split(port, "/")[1]
|
||||||
}
|
}
|
||||||
|
itemPort.Strategy = "accept"
|
||||||
datas = append(datas, itemPort)
|
datas = append(datas, itemPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stdout1, err := f.Client.Run("firewall-cmd --zone=public --list-rich-rules")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rules := strings.Split(stdout1, "\n")
|
||||||
|
for _, rule := range rules {
|
||||||
|
if len(rule) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
itemRule := f.loadInfo(rule)
|
||||||
|
if len(itemRule.Port) != 0 {
|
||||||
|
datas = append(datas, itemRule)
|
||||||
|
}
|
||||||
|
}
|
||||||
return datas, nil
|
return datas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Firewall) ListRichRules() ([]FireInfo, error) {
|
func (f *Firewall) ListAddress() ([]FireInfo, error) {
|
||||||
stdout, err := cmd.Exec("firewall-cmd --zone=public --list-rich-rules")
|
stdout, err := f.Client.Run("firewall-cmd --zone=public --list-rich-rules")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -74,29 +98,16 @@ func (f *Firewall) ListRichRules() ([]FireInfo, error) {
|
|||||||
if len(rule) == 0 {
|
if len(rule) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var itemRule FireInfo
|
itemRule := f.loadInfo(rule)
|
||||||
ruleInfo := strings.Split(strings.ReplaceAll(rule, "\"", ""), " ")
|
if len(itemRule.Port) == 0 {
|
||||||
for _, item := range ruleInfo {
|
|
||||||
switch {
|
|
||||||
case strings.Contains(item, "family="):
|
|
||||||
itemRule.Family = strings.ReplaceAll(item, "family=", "")
|
|
||||||
case strings.Contains(item, "address="):
|
|
||||||
itemRule.Address = strings.ReplaceAll(item, "address=", "")
|
|
||||||
case strings.Contains(item, "port="):
|
|
||||||
itemRule.Port = strings.ReplaceAll(item, "port=", "")
|
|
||||||
case strings.Contains(item, "protocol="):
|
|
||||||
itemRule.Protocol = strings.ReplaceAll(item, "protocol=", "")
|
|
||||||
case item == "accept" || item == "drop":
|
|
||||||
itemRule.Strategy = item
|
|
||||||
}
|
|
||||||
}
|
|
||||||
datas = append(datas, itemRule)
|
datas = append(datas, itemRule)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return datas, nil
|
return datas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Firewall) Port(port FireInfo, operation string) error {
|
func (f *Firewall) Port(port FireInfo, operation string) error {
|
||||||
stdout, err := cmd.Execf("firewall-cmd --zone=public --%s-port=%s/%s --permanent", operation, port.Port, port.Protocol)
|
stdout, err := f.Client.Run(fmt.Sprintf("firewall-cmd --zone=public --%s-port=%s/%s --permanent", operation, port.Port, port.Protocol))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s port failed, err: %s", operation, stdout)
|
return fmt.Errorf("%s port failed, err: %s", operation, stdout)
|
||||||
}
|
}
|
||||||
@ -119,7 +130,7 @@ func (f *Firewall) RichRules(rule FireInfo, operation string) error {
|
|||||||
}
|
}
|
||||||
ruleStr += rule.Strategy
|
ruleStr += rule.Strategy
|
||||||
|
|
||||||
stdout, err := cmd.Execf("firewall-cmd --zone=public --%s-rich-rule '%s' --permanent", operation, ruleStr)
|
stdout, err := f.Client.Run(fmt.Sprintf("firewall-cmd --zone=public --%s-rich-rule '%s' --permanent", operation, ruleStr))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s rich rules failed, err: %s", operation, stdout)
|
return fmt.Errorf("%s rich rules failed, err: %s", operation, stdout)
|
||||||
}
|
}
|
||||||
@ -135,7 +146,7 @@ func (f *Firewall) PortForward(info Forward, operation string) error {
|
|||||||
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 --%s-forward-port=port=%s:proto=%s:toaddr=%s:toport=%s --permanent", operation, info.Port, info.Protocol, info.Address, info.Target)
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, err := cmd.Exec(ruleStr)
|
stdout, err := f.Client.Run(ruleStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s port forward failed, err: %s", operation, stdout)
|
return fmt.Errorf("%s port forward failed, err: %s", operation, stdout)
|
||||||
}
|
}
|
||||||
@ -144,3 +155,23 @@ func (f *Firewall) PortForward(info Forward, operation string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Firewall) loadInfo(line string) FireInfo {
|
||||||
|
var itemRule FireInfo
|
||||||
|
ruleInfo := strings.Split(strings.ReplaceAll(line, "\"", ""), " ")
|
||||||
|
for _, item := range ruleInfo {
|
||||||
|
switch {
|
||||||
|
case strings.Contains(item, "family="):
|
||||||
|
itemRule.Family = strings.ReplaceAll(item, "family=", "")
|
||||||
|
case strings.Contains(item, "address="):
|
||||||
|
itemRule.Address = strings.ReplaceAll(item, "address=", "")
|
||||||
|
case strings.Contains(item, "port="):
|
||||||
|
itemRule.Port = strings.ReplaceAll(item, "port=", "")
|
||||||
|
case strings.Contains(item, "protocol="):
|
||||||
|
itemRule.Protocol = strings.ReplaceAll(item, "protocol=", "")
|
||||||
|
case item == "accept" || item == "drop":
|
||||||
|
itemRule.Strategy = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return itemRule
|
||||||
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@ -11,41 +10,28 @@ import (
|
|||||||
|
|
||||||
func TestFire(t *testing.T) {
|
func TestFire(t *testing.T) {
|
||||||
ConnInfo := ssh.ConnInfo{
|
ConnInfo := ssh.ConnInfo{
|
||||||
|
Addr: "172.16.10.234",
|
||||||
User: "ubuntu",
|
User: "ubuntu",
|
||||||
AuthMode: "password",
|
AuthMode: "password",
|
||||||
Port: 22,
|
Port: 22,
|
||||||
}
|
}
|
||||||
output, err := ConnInfo.Run("sudo ufw status numbered")
|
output, err := ConnInfo.Run("sudo ufw status verbose")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lines := strings.Split(string(output), "\n")
|
lines := strings.Split(string(output), "\n")
|
||||||
var rules []UfwRule
|
var datas []FireInfo
|
||||||
|
isStart := false
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
if line == "" || !strings.HasPrefix(line, "[") {
|
if strings.HasPrefix(line, "--") {
|
||||||
|
isStart = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fields := strings.Fields(line)
|
if !isStart {
|
||||||
rule := UfwRule{Status: fields[0], From: fields[1], To: fields[2], Proto: fields[3], Comment: strings.Join(fields[4:], " ")}
|
continue
|
||||||
rules = append(rules, rule)
|
|
||||||
}
|
}
|
||||||
ufwStatus := UfwStatus{Rules: rules}
|
|
||||||
ufwStatusJSON, err := json.MarshalIndent(ufwStatus, "", " ")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error:", err)
|
|
||||||
}
|
}
|
||||||
fmt.Println(string(ufwStatusJSON))
|
fmt.Println(datas)
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
type UfwRule struct {
|
|
||||||
Status string `json:"status"`
|
|
||||||
From string `json:"from"`
|
|
||||||
To string `json:"to"`
|
|
||||||
Proto string `json:"proto"`
|
|
||||||
Comment string `json:"comment"`
|
|
||||||
}
|
|
||||||
type UfwStatus struct {
|
|
||||||
Rules []UfwRule `json:"rules"`
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package client
|
package client
|
||||||
|
|
||||||
type FireInfo struct {
|
type FireInfo struct {
|
||||||
Family string
|
Family string `json:"family"` // ipv4 ipv6
|
||||||
Address string
|
Address string `json:"address"` // Anywhere
|
||||||
Port string
|
Port string `json:"port"`
|
||||||
Protocol string
|
Protocol string `json:"protocol"` // tcp udp tcp/upd
|
||||||
Strategy string
|
Strategy string `json:"strategy"` // accept drop
|
||||||
}
|
}
|
||||||
|
|
||||||
type Forward struct {
|
type Forward struct {
|
||||||
Protocol string
|
Protocol string `json:"protocol"`
|
||||||
Address string
|
Address string `json:"address"`
|
||||||
Port string
|
Port string `json:"port"`
|
||||||
Target string
|
Target string `json:"target"`
|
||||||
}
|
}
|
||||||
|
@ -4,17 +4,25 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
"github.com/1Panel-dev/1Panel/backend/utils/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Ufw struct{}
|
type Ufw struct {
|
||||||
|
Client ssh.ConnInfo
|
||||||
|
}
|
||||||
|
|
||||||
func NewUfw() (*Ufw, error) {
|
func NewUfw() (*Ufw, error) {
|
||||||
return &Ufw{}, nil
|
ConnInfo := ssh.ConnInfo{
|
||||||
|
Addr: "172.16.10.234",
|
||||||
|
User: "ubuntu",
|
||||||
|
AuthMode: "password",
|
||||||
|
Port: 22,
|
||||||
|
}
|
||||||
|
return &Ufw{Client: ConnInfo}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Ufw) Status() (string, error) {
|
func (f *Ufw) Status() (string, error) {
|
||||||
stdout, err := cmd.Exec("sudo ufw status")
|
stdout, err := f.Client.Run("sudo ufw status")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("load the firewall status failed, err: %s", stdout)
|
return "", fmt.Errorf("load the firewall status failed, err: %s", stdout)
|
||||||
}
|
}
|
||||||
@ -25,7 +33,7 @@ func (f *Ufw) Status() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Ufw) Start() error {
|
func (f *Ufw) Start() error {
|
||||||
stdout, err := cmd.Exec("sudo ufw enable")
|
stdout, err := f.Client.Run("sudo ufw enable")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("enable the firewall failed, err: %s", stdout)
|
return fmt.Errorf("enable the firewall failed, err: %s", stdout)
|
||||||
}
|
}
|
||||||
@ -33,7 +41,7 @@ func (f *Ufw) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Ufw) Stop() error {
|
func (f *Ufw) Stop() error {
|
||||||
stdout, err := cmd.Exec("sudo ufw disable")
|
stdout, err := f.Client.Run("sudo ufw disable")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("stop the firewall failed, err: %s", stdout)
|
return fmt.Errorf("stop the firewall failed, err: %s", stdout)
|
||||||
}
|
}
|
||||||
@ -41,7 +49,7 @@ func (f *Ufw) Stop() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Ufw) Reload() error {
|
func (f *Ufw) Reload() error {
|
||||||
stdout, err := cmd.Exec("sudo ufw reload")
|
stdout, err := f.Client.Run("sudo ufw reload")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("reload firewall failed, err: %s", stdout)
|
return fmt.Errorf("reload firewall failed, err: %s", stdout)
|
||||||
}
|
}
|
||||||
@ -49,51 +57,49 @@ func (f *Ufw) Reload() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Ufw) ListPort() ([]FireInfo, error) {
|
func (f *Ufw) ListPort() ([]FireInfo, error) {
|
||||||
stdout, err := cmd.Exec("firewall-cmd --zone=public --list-ports")
|
stdout, err := f.Client.Run("sudo ufw status verbose")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ports := strings.Split(strings.ReplaceAll(stdout, "\n", ""), " ")
|
portInfos := strings.Split(strings.ReplaceAll(stdout, "\n", ""), " ")
|
||||||
var datas []FireInfo
|
var datas []FireInfo
|
||||||
for _, port := range ports {
|
isStart := false
|
||||||
var itemPort FireInfo
|
for _, line := range portInfos {
|
||||||
if strings.Contains(port, "/") {
|
if strings.HasPrefix(line, "--") {
|
||||||
itemPort.Port = strings.Split(port, "/")[0]
|
isStart = true
|
||||||
itemPort.Protocol = strings.Split(port, "/")[1]
|
continue
|
||||||
|
}
|
||||||
|
if !isStart {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
itemFire := f.loadInfo(line, "port")
|
||||||
|
if len(itemFire.Address) != 0 {
|
||||||
|
datas = append(datas, itemFire)
|
||||||
}
|
}
|
||||||
datas = append(datas, itemPort)
|
|
||||||
}
|
}
|
||||||
return datas, nil
|
return datas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Ufw) ListRichRules() ([]FireInfo, error) {
|
func (f *Ufw) ListAddress() ([]FireInfo, error) {
|
||||||
stdout, err := cmd.Exec("firewall-cmd --zone=public --list-rich-rules")
|
stdout, err := f.Client.Run("sudo ufw status verbose")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
portInfos := strings.Split(strings.ReplaceAll(stdout, "\n", ""), " ")
|
||||||
var datas []FireInfo
|
var datas []FireInfo
|
||||||
rules := strings.Split(stdout, "\n")
|
isStart := false
|
||||||
for _, rule := range rules {
|
for _, line := range portInfos {
|
||||||
if len(rule) == 0 {
|
if strings.HasPrefix(line, "--") {
|
||||||
|
isStart = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var itemRule FireInfo
|
if !isStart {
|
||||||
ruleInfo := strings.Split(strings.ReplaceAll(rule, "\"", ""), " ")
|
continue
|
||||||
for _, item := range ruleInfo {
|
|
||||||
switch {
|
|
||||||
case strings.Contains(item, "family="):
|
|
||||||
itemRule.Family = strings.ReplaceAll(item, "family=", "")
|
|
||||||
case strings.Contains(item, "address="):
|
|
||||||
itemRule.Address = strings.ReplaceAll(item, "address=", "")
|
|
||||||
case strings.Contains(item, "port="):
|
|
||||||
itemRule.Port = strings.ReplaceAll(item, "port=", "")
|
|
||||||
case strings.Contains(item, "protocol="):
|
|
||||||
itemRule.Protocol = strings.ReplaceAll(item, "protocol=", "")
|
|
||||||
case item == "accept" || item == "drop":
|
|
||||||
itemRule.Strategy = item
|
|
||||||
}
|
}
|
||||||
|
itemFire := f.loadInfo(line, "address")
|
||||||
|
if len(itemFire.Address) != 0 {
|
||||||
|
datas = append(datas, itemFire)
|
||||||
}
|
}
|
||||||
datas = append(datas, itemRule)
|
|
||||||
}
|
}
|
||||||
return datas, nil
|
return datas, nil
|
||||||
}
|
}
|
||||||
@ -108,11 +114,11 @@ func (f *Ufw) Port(port FireInfo, operation string) error {
|
|||||||
return fmt.Errorf("unsupport operation %s", operation)
|
return fmt.Errorf("unsupport operation %s", operation)
|
||||||
}
|
}
|
||||||
|
|
||||||
command := fmt.Sprintf("ufw %s %s", operation, port.Port)
|
command := fmt.Sprintf("sudo ufw %s %s", operation, port.Port)
|
||||||
if len(port.Protocol) != 0 {
|
if len(port.Protocol) != 0 {
|
||||||
command += fmt.Sprintf("/%s", port.Protocol)
|
command += fmt.Sprintf("/%s", port.Protocol)
|
||||||
}
|
}
|
||||||
stdout, err := cmd.Exec(command)
|
stdout, err := f.Client.Run(command)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s port failed, err: %s", operation, stdout)
|
return fmt.Errorf("%s port failed, err: %s", operation, stdout)
|
||||||
}
|
}
|
||||||
@ -120,25 +126,21 @@ func (f *Ufw) Port(port FireInfo, operation string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Ufw) RichRules(rule FireInfo, operation string) error {
|
func (f *Ufw) RichRules(rule FireInfo, operation string) error {
|
||||||
ruleStr := "rule family=ipv4 "
|
ruleStr := "sudo ufw "
|
||||||
|
if len(rule.Protocol) != 0 {
|
||||||
|
ruleStr += fmt.Sprintf("proto %s ", rule.Protocol)
|
||||||
|
}
|
||||||
if len(rule.Address) != 0 {
|
if len(rule.Address) != 0 {
|
||||||
ruleStr += fmt.Sprintf("source address=%s ", rule.Address)
|
ruleStr += fmt.Sprintf("from %s ", rule.Address)
|
||||||
}
|
}
|
||||||
if len(rule.Port) != 0 {
|
if len(rule.Port) != 0 {
|
||||||
ruleStr += fmt.Sprintf("port port=%s ", rule.Port)
|
ruleStr += fmt.Sprintf("to any port %s ", rule.Port)
|
||||||
}
|
}
|
||||||
if len(rule.Protocol) != 0 {
|
|
||||||
ruleStr += fmt.Sprintf("protocol=%s ", rule.Protocol)
|
|
||||||
}
|
|
||||||
ruleStr += rule.Strategy
|
|
||||||
|
|
||||||
stdout, err := cmd.Execf("firewall-cmd --zone=public --%s-rich-rule '%s' --permanent", operation, ruleStr)
|
stdout, err := f.Client.Run(ruleStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s rich rules failed, err: %s", operation, stdout)
|
return fmt.Errorf("%s rich rules failed, err: %s", operation, stdout)
|
||||||
}
|
}
|
||||||
if err := f.Reload(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +150,7 @@ func (f *Ufw) PortForward(info Forward, operation string) error {
|
|||||||
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 --%s-forward-port=port=%s:proto=%s:toaddr=%s:toport=%s --permanent", operation, info.Port, info.Protocol, info.Address, info.Target)
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, err := cmd.Exec(ruleStr)
|
stdout, err := f.Client.Run(ruleStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%s port forward failed, err: %s", operation, stdout)
|
return fmt.Errorf("%s port forward failed, err: %s", operation, stdout)
|
||||||
}
|
}
|
||||||
@ -157,3 +159,49 @@ func (f *Ufw) PortForward(info Forward, operation string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Ufw) loadInfo(line string, fireType string) FireInfo {
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
var itemInfo FireInfo
|
||||||
|
if len(fields) < 4 {
|
||||||
|
return itemInfo
|
||||||
|
}
|
||||||
|
if fields[0] == "Anywhere" && fireType == "port" {
|
||||||
|
itemInfo.Strategy = "drop"
|
||||||
|
if fields[2] == "ALLOW" {
|
||||||
|
itemInfo.Strategy = "accept"
|
||||||
|
}
|
||||||
|
itemInfo.Address = fields[3]
|
||||||
|
return itemInfo
|
||||||
|
}
|
||||||
|
if strings.Contains(fields[0], "/") {
|
||||||
|
itemInfo.Port = strings.Split(fields[0], "/")[0]
|
||||||
|
itemInfo.Protocol = strings.Split(fields[0], "/")[1]
|
||||||
|
} else {
|
||||||
|
itemInfo.Port = fields[0]
|
||||||
|
itemInfo.Protocol = "tcp/udp"
|
||||||
|
}
|
||||||
|
|
||||||
|
if fields[1] == "(v6)" {
|
||||||
|
if len(fields) < 5 {
|
||||||
|
return itemInfo
|
||||||
|
}
|
||||||
|
itemInfo.Family = "ipv6"
|
||||||
|
if fields[2] == "ALLOW" {
|
||||||
|
itemInfo.Strategy = "accept"
|
||||||
|
} else {
|
||||||
|
itemInfo.Strategy = "drop"
|
||||||
|
}
|
||||||
|
itemInfo.Address = fields[4]
|
||||||
|
} else {
|
||||||
|
itemInfo.Family = "ipv4"
|
||||||
|
if fields[1] == "ALLOW" {
|
||||||
|
itemInfo.Strategy = "accept"
|
||||||
|
} else {
|
||||||
|
itemInfo.Strategy = "drop"
|
||||||
|
}
|
||||||
|
itemInfo.Address = fields[3]
|
||||||
|
}
|
||||||
|
|
||||||
|
return itemInfo
|
||||||
|
}
|
||||||
|
@ -52,4 +52,29 @@ export namespace Host {
|
|||||||
groupID: number;
|
groupID: number;
|
||||||
info?: string;
|
info?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RuleSearch extends ReqPage {
|
||||||
|
info: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
export interface RuleInfo extends ReqPage {
|
||||||
|
family: string;
|
||||||
|
address: string;
|
||||||
|
port: string;
|
||||||
|
protocol: string;
|
||||||
|
strategy: string;
|
||||||
|
}
|
||||||
|
export interface RulePort {
|
||||||
|
operation: string;
|
||||||
|
address: string;
|
||||||
|
port: string;
|
||||||
|
source: string;
|
||||||
|
protocol: string;
|
||||||
|
strategy: string;
|
||||||
|
}
|
||||||
|
export interface RuleIP {
|
||||||
|
operation: string;
|
||||||
|
address: string;
|
||||||
|
strategy: string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,3 +70,14 @@ export const editCommand = (params: Command.CommandOperate) => {
|
|||||||
export const deleteCommand = (params: { ids: number[] }) => {
|
export const deleteCommand = (params: { ids: number[] }) => {
|
||||||
return http.post(`/hosts/command/del`, params);
|
return http.post(`/hosts/command/del`, params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// firewall
|
||||||
|
export const searchFireRule = (params: Host.RuleSearch) => {
|
||||||
|
return http.post<ResPage<Host.RuleInfo>>(`/hosts/firewall/search`, params);
|
||||||
|
};
|
||||||
|
export const operatePortRule = (params: Host.RulePort) => {
|
||||||
|
return http.post<Host.RulePort>(`/hosts/firewall/port`, params);
|
||||||
|
};
|
||||||
|
export const operateIPRule = (params: Host.RuleIP) => {
|
||||||
|
return http.post<Host.RuleIP>(`/hosts/firewall/ip`, params);
|
||||||
|
};
|
||||||
|
@ -215,7 +215,6 @@ const message = {
|
|||||||
container: '容器',
|
container: '容器',
|
||||||
cronjob: '计划任务',
|
cronjob: '计划任务',
|
||||||
host: '主机',
|
host: '主机',
|
||||||
security: '安全',
|
|
||||||
files: '文件',
|
files: '文件',
|
||||||
monitor: '监控',
|
monitor: '监控',
|
||||||
terminal: '终端',
|
terminal: '终端',
|
||||||
@ -1181,6 +1180,19 @@ const message = {
|
|||||||
argsCheck: 'GET 参数校验',
|
argsCheck: 'GET 参数校验',
|
||||||
postCheck: 'POST 参数校验',
|
postCheck: 'POST 参数校验',
|
||||||
cookieBlockList: 'Cookie 黑名单',
|
cookieBlockList: 'Cookie 黑名单',
|
||||||
|
|
||||||
|
firewall: '防火墙',
|
||||||
|
protocol: '协议',
|
||||||
|
port: '端口',
|
||||||
|
strategy: '策略',
|
||||||
|
accept: '允许',
|
||||||
|
drop: '拒绝',
|
||||||
|
source: '来源',
|
||||||
|
anyWhere: '所有 IP',
|
||||||
|
address: '指定 IP',
|
||||||
|
allIP: '所有 IP',
|
||||||
|
portRule: '端口规则',
|
||||||
|
ipRule: 'IP 规则',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
export default {
|
export default {
|
||||||
|
@ -29,6 +29,25 @@ const hostRouter = {
|
|||||||
requiresAuth: false,
|
requiresAuth: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/hosts/firewall/port',
|
||||||
|
name: 'FirewallPort',
|
||||||
|
component: () => import('@/views/host/firewall/port/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'menu.firewall',
|
||||||
|
requiresAuth: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/hosts/firewall/ip',
|
||||||
|
name: 'FirewallIP',
|
||||||
|
component: () => import('@/views/host/firewall/ip/index.vue'),
|
||||||
|
hidden: true,
|
||||||
|
meta: {
|
||||||
|
title: 'menu.toolbox',
|
||||||
|
requiresAuth: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/hosts/terminal',
|
path: '/hosts/terminal',
|
||||||
name: 'Terminal',
|
name: 'Terminal',
|
||||||
|
25
frontend/src/views/host/firewall/index.vue
Normal file
25
frontend/src/views/host/firewall/index.vue
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<RouterButton :buttons="buttons" />
|
||||||
|
<LayoutContent>
|
||||||
|
<router-view></router-view>
|
||||||
|
</LayoutContent>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import i18n from '@/lang';
|
||||||
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
|
import RouterButton from '@/components/router-button/index.vue';
|
||||||
|
|
||||||
|
const buttons = [
|
||||||
|
{
|
||||||
|
label: i18n.global.t('firewall.portRule'),
|
||||||
|
path: '/hosts/firewall/port',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: i18n.global.t('firewall.ipRule'),
|
||||||
|
path: '/hosts/firewall/ip',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
</script>
|
101
frontend/src/views/host/firewall/ip/index.vue
Normal file
101
frontend/src/views/host/firewall/ip/index.vue
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<FireRouter />
|
||||||
|
<LayoutContent v-loading="loading" :title="$t('firewall.firewall')">
|
||||||
|
<template #toolbar>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="20">
|
||||||
|
<el-button
|
||||||
|
class="tag-button"
|
||||||
|
:class="activeTag === 'port' ? '' : 'no-active'"
|
||||||
|
@click="changeTag('port')"
|
||||||
|
:type="activeTag === 'port' ? 'primary' : ''"
|
||||||
|
:plain="activeTag !== 'port'"
|
||||||
|
>
|
||||||
|
{{ $t('firewall.portRule') }}
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
class="tag-button"
|
||||||
|
:class="activeTag === 'ip' ? '' : 'no-active'"
|
||||||
|
@click="changeTag('ip')"
|
||||||
|
:type="activeTag === 'ip' ? 'primary' : ''"
|
||||||
|
:plain="activeTag !== 'ip'"
|
||||||
|
>
|
||||||
|
{{ $t('firewall.ipRule') }}
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
<template #main>
|
||||||
|
<ComplexTable
|
||||||
|
:pagination-config="paginationConfig"
|
||||||
|
v-model:selects="selects"
|
||||||
|
@search="search"
|
||||||
|
:data="data"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" fix />
|
||||||
|
<el-table-column :label="$t('firewall.protocol')" :min-width="90" prop="protocol" />
|
||||||
|
<el-table-column :label="$t('firewall.port')" :min-width="120" prop="port" />
|
||||||
|
<el-table-column :min-width="80" :label="$t('firewall.strategy')" prop="strategy">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag v-if="row.strategy === 'accept'" type="success">{{ $t('firewall.accept') }}</el-tag>
|
||||||
|
<el-tag v-if="row.strategy === 'drop'" type="danger">{{ $t('firewall.drop') }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :min-width="80" :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>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</ComplexTable>
|
||||||
|
</template>
|
||||||
|
</LayoutContent>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import FireRouter from '@/views/host/firewall/index.vue';
|
||||||
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
|
import { searchFireRule } from '@/api/modules/host';
|
||||||
|
|
||||||
|
const loading = ref();
|
||||||
|
const activeTag = ref('port');
|
||||||
|
const selects = ref<any>([]);
|
||||||
|
|
||||||
|
const data = ref();
|
||||||
|
const paginationConfig = reactive({
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const search = async () => {
|
||||||
|
let params = {
|
||||||
|
type: activeTag.value,
|
||||||
|
info: '',
|
||||||
|
page: paginationConfig.currentPage,
|
||||||
|
pageSize: paginationConfig.pageSize,
|
||||||
|
};
|
||||||
|
loading.value = true;
|
||||||
|
await searchFireRule(params)
|
||||||
|
.then((res) => {
|
||||||
|
loading.value = false;
|
||||||
|
data.value = res.data.items || [];
|
||||||
|
paginationConfig.total = res.data.total;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeTag = async (type: string) => {
|
||||||
|
activeTag.value = type;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
search();
|
||||||
|
});
|
||||||
|
</script>
|
114
frontend/src/views/host/firewall/port/create/index.vue
Normal file
114
frontend/src/views/host/firewall/port/create/index.vue
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<template>
|
||||||
|
<el-drawer v-model="drawerVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||||
|
<template #header>
|
||||||
|
<DrawerHeader :header="$t('firewall.portRule')" :back="handleClose" />
|
||||||
|
</template>
|
||||||
|
<el-form ref="formRef" label-position="top" :model="dialogData.rowData" :rules="rules">
|
||||||
|
<el-row type="flex" justify="center">
|
||||||
|
<el-col :span="22">
|
||||||
|
<el-form-item :label="$t('firewall.protocol')" prop="protocol">
|
||||||
|
<el-select style="width: 100%" v-model="dialogData.rowData!.protocol">
|
||||||
|
<el-option value="tcp" label="tcp" />
|
||||||
|
<el-option value="udp" label="udp" />
|
||||||
|
<el-option value="tcp/udp" label="tcp/udp" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="$t('firewall.port')" prop="port">
|
||||||
|
<el-input clearable v-model.trim="dialogData.rowData!.port" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="$t('firewall.source')" prop="source">
|
||||||
|
<el-radio-group v-model="dialogData.rowData!.source">
|
||||||
|
<el-radio label="anyWhere">{{ $t('firewall.anyWhere') }}</el-radio>
|
||||||
|
<el-radio label="address">{{ $t('firewall.address') }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item
|
||||||
|
:label="$t('firewall.address')"
|
||||||
|
v-if="dialogData.rowData!.source === 'address'"
|
||||||
|
prop="address"
|
||||||
|
>
|
||||||
|
<el-input v-model="dialogData.rowData!.address" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item :label="$t('firewall.strategy')" prop="strategy">
|
||||||
|
<el-radio-group v-model="dialogData.rowData!.strategy">
|
||||||
|
<el-radio label="accept">{{ $t('firewall.accept') }}</el-radio>
|
||||||
|
<el-radio label="drop">{{ $t('firewall.drop') }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="drawerVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
|
||||||
|
<el-button type="primary" @click="onSubmit(formRef)">
|
||||||
|
{{ $t('commons.button.confirm') }}
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { reactive, ref } from 'vue';
|
||||||
|
import { Rules } from '@/global/form-rules';
|
||||||
|
import i18n from '@/lang';
|
||||||
|
import { ElForm } from 'element-plus';
|
||||||
|
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||||
|
import { MsgSuccess } from '@/utils/message';
|
||||||
|
import { Host } from '@/api/interface/host';
|
||||||
|
import { operatePortRule } from '@/api/modules/host';
|
||||||
|
|
||||||
|
interface DialogProps {
|
||||||
|
title: string;
|
||||||
|
rowData?: Host.RulePort;
|
||||||
|
getTableList?: () => Promise<any>;
|
||||||
|
}
|
||||||
|
const title = ref<string>('');
|
||||||
|
const drawerVisiable = ref(false);
|
||||||
|
const dialogData = ref<DialogProps>({
|
||||||
|
title: '',
|
||||||
|
});
|
||||||
|
const acceptParams = (params: DialogProps): void => {
|
||||||
|
dialogData.value = params;
|
||||||
|
title.value = i18n.global.t('commons.button.' + dialogData.value.title);
|
||||||
|
drawerVisiable.value = true;
|
||||||
|
};
|
||||||
|
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
drawerVisiable.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const rules = reactive({
|
||||||
|
protocol: [Rules.requiredSelect],
|
||||||
|
port: [Rules.requiredInput],
|
||||||
|
address: [Rules.requiredInput],
|
||||||
|
});
|
||||||
|
|
||||||
|
type FormInstance = InstanceType<typeof ElForm>;
|
||||||
|
const formRef = ref<FormInstance>();
|
||||||
|
|
||||||
|
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.validate(async (valid) => {
|
||||||
|
if (!valid) return;
|
||||||
|
if (!dialogData.value.rowData) return;
|
||||||
|
if (dialogData.value.title === 'create') {
|
||||||
|
await operatePortRule(dialogData.value.rowData);
|
||||||
|
}
|
||||||
|
|
||||||
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
|
emit('search');
|
||||||
|
drawerVisiable.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
acceptParams,
|
||||||
|
});
|
||||||
|
</script>
|
141
frontend/src/views/host/firewall/port/index.vue
Normal file
141
frontend/src/views/host/firewall/port/index.vue
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<FireRouter />
|
||||||
|
<LayoutContent v-loading="loading" :title="$t('firewall.firewall')">
|
||||||
|
<template #toolbar>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="20">
|
||||||
|
<el-button type="primary" @click="onOpenDialog('create')">
|
||||||
|
{{ $t('commons.button.create') }}{{ $t('firewall.portRule') }}
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
<template #main>
|
||||||
|
<ComplexTable
|
||||||
|
:pagination-config="paginationConfig"
|
||||||
|
v-model:selects="selects"
|
||||||
|
@search="search"
|
||||||
|
:data="data"
|
||||||
|
>
|
||||||
|
<el-table-column type="selection" fix />
|
||||||
|
<el-table-column :label="$t('firewall.protocol')" :min-width="90" prop="protocol" />
|
||||||
|
<el-table-column :label="$t('firewall.port')" :min-width="120" prop="port" />
|
||||||
|
<el-table-column :min-width="80" :label="$t('firewall.strategy')" prop="strategy">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-tag v-if="row.strategy === 'accept'" type="success">{{ $t('firewall.accept') }}</el-tag>
|
||||||
|
<el-tag v-if="row.strategy === 'drop'" type="danger">{{ $t('firewall.drop') }}</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :min-width="80" :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>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<fu-table-operations
|
||||||
|
width="200px"
|
||||||
|
:buttons="buttons"
|
||||||
|
:ellipsis="10"
|
||||||
|
:label="$t('commons.table.operate')"
|
||||||
|
fix
|
||||||
|
/>
|
||||||
|
</ComplexTable>
|
||||||
|
</template>
|
||||||
|
</LayoutContent>
|
||||||
|
|
||||||
|
<OperatrDialog @search="search" ref="dialogRef" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import FireRouter from '@/views/host/firewall/index.vue';
|
||||||
|
import OperatrDialog from '@/views/host/firewall/port/create/index.vue';
|
||||||
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
|
import { operatePortRule, searchFireRule } from '@/api/modules/host';
|
||||||
|
import { Host } from '@/api/interface/host';
|
||||||
|
import i18n from '@/lang';
|
||||||
|
import { MsgSuccess } from '@/utils/message';
|
||||||
|
import { ElMessageBox } from 'element-plus';
|
||||||
|
|
||||||
|
const loading = ref();
|
||||||
|
const activeTag = ref('port');
|
||||||
|
const selects = ref<any>([]);
|
||||||
|
|
||||||
|
const data = ref();
|
||||||
|
const paginationConfig = reactive({
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const search = async () => {
|
||||||
|
let params = {
|
||||||
|
type: activeTag.value,
|
||||||
|
info: '',
|
||||||
|
page: paginationConfig.currentPage,
|
||||||
|
pageSize: paginationConfig.pageSize,
|
||||||
|
};
|
||||||
|
loading.value = true;
|
||||||
|
await searchFireRule(params)
|
||||||
|
.then((res) => {
|
||||||
|
loading.value = false;
|
||||||
|
data.value = res.data.items || [];
|
||||||
|
paginationConfig.total = res.data.total;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const dialogRef = ref();
|
||||||
|
const onOpenDialog = async (
|
||||||
|
title: string,
|
||||||
|
rowData: Partial<Host.RulePort> = {
|
||||||
|
protocol: 'tcp',
|
||||||
|
source: 'anyWhere',
|
||||||
|
strategy: 'accept',
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
let params = {
|
||||||
|
title,
|
||||||
|
rowData: { ...rowData },
|
||||||
|
};
|
||||||
|
dialogRef.value!.acceptParams(params);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDelete = async (row: Host.RuleInfo | null) => {
|
||||||
|
ElMessageBox.confirm(i18n.global.t('commons.msg.delete'), i18n.global.t('commons.msg.deleteTitle'), {
|
||||||
|
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||||
|
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||||
|
type: 'warning',
|
||||||
|
}).then(async () => {
|
||||||
|
let params = {
|
||||||
|
operation: 'remove',
|
||||||
|
address: row.address,
|
||||||
|
port: row.port,
|
||||||
|
source: '',
|
||||||
|
protocol: row.protocol,
|
||||||
|
strategy: row.strategy,
|
||||||
|
};
|
||||||
|
await operatePortRule(params);
|
||||||
|
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
|
search();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const buttons = [
|
||||||
|
{
|
||||||
|
label: i18n.global.t('commons.button.delete'),
|
||||||
|
click: (row: Host.RuleInfo) => {
|
||||||
|
onDelete(row);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
search();
|
||||||
|
});
|
||||||
|
</script>
|
@ -1,7 +0,0 @@
|
|||||||
<template>
|
|
||||||
<LayoutContent></LayoutContent>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import LayoutContent from '@/layout/layout-content.vue';
|
|
||||||
</script>
|
|
Loading…
x
Reference in New Issue
Block a user