Commit f9077078 authored by qiuqunfeng's avatar qiuqunfeng
Browse files

Add ListWafs endpoint and service method for WAF management

- Introduce ListWafs method in WafController to retrieve a list of WAF services
- Update WAF router to include new GET routes for listing WAFs
- Implement ListWafs method in the service layer to fetch WAF data from the database
- Enhance the MatcherExpr and WafService structures to support new functionality
parent efd47f51
......@@ -13,6 +13,7 @@ func SetWafRouter(e *gin.Engine, clusterClientManager *utils.ClusterClientManage
wafController := controller.NewWafController(clusterClientManager, db, gatewayUrl, elasticClient)
v1.GET("", wafController.Waf)
v1.GET("list", wafController.ListWafs)
v1.POST("/", wafController.CreateWaf)
v1.PUT("mode", wafController.UpdateMode)
v1.PUT("rules", wafController.UpdateRule)
......@@ -32,4 +33,5 @@ func SetWafRouter(e *gin.Engine, clusterClientManager *utils.ClusterClientManage
v2.PUT("blackwhitelist/enabling", wafController.EnableBlackWhiteList)
v2.DELETE("blackwhitelist/{id}", wafController.DeleteBlackWhiteList)
v2.GET("blackwhitelists", wafController.GetBlackWhiteLists)
v2.GET("services", wafController.ListWafs)
}
......@@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
......@@ -45,6 +46,18 @@ func (c *WafController) Waf(ctx *gin.Context) {
utils.AssembleResponse(ctx, resp, nil)
}
func (c *WafController) ListWafs(ctx *gin.Context) {
ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
wafs, err := c.service.ListWafs(ctx1)
if err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
utils.AssembleResponse(ctx, wafs, nil)
}
func (c *WafController) GetWafGatewayInfo(ctx *gin.Context) {
ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
......@@ -298,6 +311,7 @@ func (c *WafController) ListAttackLogs(ctx *gin.Context) {
filter.AttackIp = ctx.Query("attackIp")
filter.AttackType = ctx.Query("attackType")
filter.AttackApp = ctx.Query("attackApp")
filter.AttackListener = ctx.Query("attackListener")
filter.Token = ctx.Query("token")
filter.Action = ctx.Query("action")
stime := ctx.Query("startTime")
......@@ -387,13 +401,67 @@ func (c *WafController) EnableBlackWhiteList(ctx *gin.Context) {
}
func (c *WafController) DeleteBlackWhiteList(ctx *gin.Context) {
// ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// defer cancel()
ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
id := ctx.Param("id")
idUint, err := strconv.ParseUint(id, 10, 32)
if err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
err = c.service.DeleteBlackWhiteList(ctx1, uint32(idUint))
if err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
utils.AssembleResponse(ctx, nil, nil)
}
func (c *WafController) GetBlackWhiteLists(ctx *gin.Context) {
// ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
// defer cancel()
ctx1, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
limit, offset, err := getLimitAndOffset(ctx)
if err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
name := ctx.Query("name")
status := ctx.Query("status")
mode := ctx.Query("mode")
expr := ctx.Query("expr")
query := service.MatchExprQuery()
if status != "" {
statusList := strings.Split(status, ",")
if len(statusList) == 1 && statusList[0] != "" {
switch status {
case "0":
query.WithStatus(0)
case "1":
query.WithStatus(1)
}
}
}
if name != "" {
query.WithFuzzyName(name)
}
if mode != "" {
modes := strings.Split(mode, ",")
query.WithInConditionCustom("mode", modes)
}
if expr != "" {
query.WithFuzzyExpr(expr)
}
lists, err := c.service.GetBlackWhiteLists(ctx1, query, limit, offset)
if err != nil {
utils.AssembleResponse(ctx, nil, err)
return
}
utils.AssembleResponse(ctx, lists, nil)
}
......@@ -5,6 +5,7 @@ import "context"
type Service interface {
// QueryIP(ip string) (*model.IPInfo, error)
GetWaf(ctx context.Context, regionCode, namespace, gatewayName string) (*WafService, error)
ListWafs(ctx context.Context) ([]WafService, error)
GetWafGatewayInfo(ctx context.Context, req *GetWafGatewayInfoReq) (*WafService, error)
CreateWaf(ctx context.Context, req *CreateWafReq) (*WafService, error)
UpdateMode(ctx context.Context, req *UpdateModeReq) (*WafService, error)
......@@ -20,6 +21,6 @@ type Service interface {
CreateBlackWhiteList(ctx context.Context, req *MatcherExpr) error
UpdateBlackWhiteList(ctx context.Context, req *MatcherExpr) error
EnableBlackWhiteList(ctx context.Context, req *MatcherExpr) error
DeleteBlackWhiteList(ctx context.Context, req *MatcherExpr) error
GetBlackWhiteLists(ctx context.Context, req *MatcherExpr) ([]MatcherExpr, error)
DeleteBlackWhiteList(ctx context.Context, ID uint32) error
GetBlackWhiteLists(ctx context.Context, query *MatchExprQueryOption, limit int, offset int) ([]MatcherExpr, error)
}
......@@ -165,6 +165,7 @@ type IPInfoPrivateResp struct {
type WafService struct {
GatewayName string `json:"gateway_name"`
Name string `json:"name"`
Mode string `json:"mode"`
RuleNum int `json:"rule_num"`
AttackNum int `json:"attack_num"`
......@@ -328,29 +329,31 @@ type GatewayListenerResponseList struct {
}
type AttackLog struct {
Uuid string `json:"uuid"`
AttackIp string `json:"attack_ip"`
AttackedAddr string `json:"attacked_addr"`
AttackType string `json:"attack_type"`
AttackTime int64 `json:"attack_time"`
AttackedApp string `json:"attacked_app"`
ClusterKey string `json:"cluster_key"`
Action string `json:"action"`
Uuid string `json:"uuid"`
AttackIp string `json:"attack_ip"`
AttackedAddr string `json:"attacked_addr"`
AttackType string `json:"attack_type"`
AttackTime int64 `json:"attack_time"`
AttackedApp string `json:"attacked_app"`
AttackListener string `json:"attack_listener"`
ClusterKey string `json:"cluster_key"`
Action string `json:"action"`
}
type AttackLogFilter struct {
Offset int `json:"offset"`
Limit int `json:"limit"`
ServiceId int64 `json:"service_id"`
Cluster string `json:"cluster"`
AttackUrl string `json:"attack_url"`
AttackIp string `json:"attack_ip"`
AttackType string `json:"attack_type"`
AttackApp string `json:"attack_app"`
Action string `json:"action"`
Token string `json:"token"`
StartTime int64 `json:"start_time"`
EndTime int64 `json:"end_time"`
Offset int `json:"offset"`
Limit int `json:"limit"`
ServiceId int64 `json:"service_id"`
Cluster string `json:"cluster"`
AttackUrl string `json:"attack_url"`
AttackIp string `json:"attack_ip"`
AttackType string `json:"attack_type"`
AttackApp string `json:"attack_app"`
AttackListener string `json:"attack_listener"`
Action string `json:"action"`
Token string `json:"token"`
StartTime int64 `json:"start_time"`
EndTime int64 `json:"end_time"`
}
type MatcherExpr struct {
......@@ -363,3 +366,42 @@ type MatcherExpr struct {
Global bool `json:"global"`
Status int32 `json:"status"`
}
type MatchExprQueryOption struct {
WhereLikeCondition map[string]string
whereEqCondition map[string]interface{}
whereInCondition map[string]interface{}
}
func MatchExprQuery() *MatchExprQueryOption {
return &MatchExprQueryOption{
WhereLikeCondition: make(map[string]string, 3),
whereEqCondition: make(map[string]interface{}, 3),
whereInCondition: make(map[string]interface{}, 3),
}
}
func (n *MatchExprQueryOption) WithFuzzyName(name string) *MatchExprQueryOption {
n.WhereLikeCondition["name"] = name
return n
}
func (n *MatchExprQueryOption) WithFuzzyExpr(expr string) *MatchExprQueryOption {
n.WhereLikeCondition["expr"] = expr
return n
}
func (n *MatchExprQueryOption) WithStatus(status int32) *MatchExprQueryOption {
n.whereEqCondition["status"] = status
return n
}
func (n *MatchExprQueryOption) WithMode(mode string) *MatchExprQueryOption {
n.whereEqCondition["mode"] = mode
return n
}
func (q *MatchExprQueryOption) WithInConditionCustom(column string, value interface{}) *MatchExprQueryOption {
q.whereInCondition[column] = value
return q
}
......@@ -13,6 +13,7 @@ import (
"strconv"
"strings"
"sync"
"time"
jsoniter "github.com/json-iterator/go"
"github.com/olivere/elastic/v7"
......@@ -79,6 +80,17 @@ func (s *wafService) GetWaf(ctx context.Context, regionCode, namespace, gatewayN
}, nil
}
func (s *wafService) ListWafs(ctx context.Context) ([]WafService, error) {
var wafs []WafService
if err := s.db.Model(&model.WafService{}).Find(&wafs).Error; err != nil {
return nil, err
}
for i, waf := range wafs {
wafs[i].Name = waf.GatewayName
}
return wafs, nil
}
func (s *wafService) GetWafGatewayInfo(ctx context.Context, req *GetWafGatewayInfoReq) (*WafService, error) {
wafService := &model.WafService{}
err := s.db.Model(&model.WafService{}).Where("gateway_name = ? AND namespace = ? AND region_code = ?", req.GatewayName, req.Namespace, req.RegionCode).First(wafService).Error
......@@ -852,14 +864,15 @@ func (s *wafService) ListAttackLogs(ctx context.Context, req *AttackLogFilter) (
attackLogs := make([]AttackLog, len(list))
for i, wafDetection := range list {
attackLogs[i] = AttackLog{
Uuid: wafDetection.ID,
AttackTime: wafDetection.AttackTime,
AttackIp: wafDetection.AttackIP,
AttackedApp: wafDetection.AttackedApp,
AttackType: wafDetection.AttackType,
Action: wafDetection.Action,
ClusterKey: wafDetection.ClusterKey,
AttackedAddr: wafDetection.AttackedURL,
Uuid: wafDetection.ID,
AttackTime: wafDetection.AttackTime,
AttackIp: wafDetection.AttackIP,
AttackedApp: wafDetection.AttackedApp,
AttackListener: wafDetection.ResName,
AttackType: wafDetection.AttackType,
Action: wafDetection.Action,
ClusterKey: wafDetection.ClusterKey,
AttackedAddr: wafDetection.AttackedURL,
}
}
return attackLogs, pageToken, nil
......@@ -1021,10 +1034,84 @@ func (s *wafService) EnableBlackWhiteList(ctx context.Context, req *MatcherExpr)
return nil
}
func (s *wafService) DeleteBlackWhiteList(ctx context.Context, req *MatcherExpr) error {
func (s *wafService) deleteConfigMap(ctx context.Context, id uint32, regionCode string, wafSvc []model.WafService) error {
client := s.clusterClientManager.GetClient(regionCode)
if client == nil {
return fmt.Errorf("failed to get cluster client")
}
name := fmt.Sprintf("waf-black-white-list-%d", id)
return client.Clientset.CoreV1().ConfigMaps(wafSvc[0].Namespace).Delete(ctx, name, metav1.DeleteOptions{})
}
func (s *wafService) DeleteBlackWhiteList(ctx context.Context, ID uint32) error {
matcherExpr := model.MatcherExpr{}
err := s.db.WithContext(ctx).Where("id = ?", ID).First(&matcherExpr).Error
if err != nil {
return err
}
svcMap, err := s.getWafServiceMap(ctx, &MatcherExpr{
ID: ID,
Name: matcherExpr.Name,
Scope: matcherExpr.Scope,
Mode: matcherExpr.Mode,
Expr: matcherExpr.Expr,
Global: matcherExpr.Global,
})
if err != nil {
return err
}
for regionCode, wafServices := range svcMap {
err := s.deleteConfigMap(ctx, ID, regionCode, wafServices)
if err != nil {
return err
}
}
err = s.db.WithContext(ctx).Delete(&model.MatcherExpr{}, ID).Error
if err != nil {
return err
}
return nil
}
func (s *wafService) GetBlackWhiteLists(ctx context.Context, req *MatcherExpr) ([]MatcherExpr, error) {
return nil, nil
func GetLikeExpr(s string) string {
sb := strings.Builder{}
sb.WriteByte('%')
sb.WriteString(s)
sb.WriteByte('%')
return sb.String()
}
func (s *wafService) GetBlackWhiteLists(ctx context.Context, query *MatchExprQueryOption, limit int, offset int) ([]MatcherExpr, error) {
oneCtx, oneCancel := context.WithTimeout(ctx, 750*time.Millisecond)
defer oneCancel()
exprs := []model.MatcherExpr{}
db := s.db.WithContext(oneCtx).Model(&model.MatcherExpr{})
if len(query.whereEqCondition) > 0 {
db = db.Where(query.whereEqCondition)
}
for column, val := range query.WhereLikeCondition {
db = db.Where(fmt.Sprintf("%s LIKE ?", column), GetLikeExpr(val))
}
for column, val := range query.whereInCondition {
db = db.Where(fmt.Sprintf("%s in ?", column), val)
}
if limit > 0 && offset >= 0 {
db = db.Offset(offset).Limit(limit)
}
err := db.Order("updated_at DESC").Find(&exprs).Error
if err != nil {
return nil, err
}
exprsResp := []MatcherExpr{}
for _, expr := range exprs {
exprsResp = append(exprsResp, MatcherExpr{
ID: expr.ID,
Name: expr.Name,
})
}
return exprsResp, nil
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment