From a1e93303f975cc6d3152b56604fd92e71d1e6cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=A5=A5=E8=B6=85?= Date: Fri, 26 Feb 2021 16:33:58 +0800 Subject: [PATCH] =?UTF-8?q?WAF=E5=8A=A8=E4=BD=9C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=98=BE=E7=A4=BAHTML=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/iplibrary/action_base.go | 6 +++ internal/iplibrary/action_html.go | 55 ++++++++++++++++++++++++++ internal/iplibrary/action_interface.go | 4 ++ internal/iplibrary/action_manager.go | 17 ++++++-- internal/iplibrary/ip_list.go | 25 +++++++++--- internal/nodes/http_request_waf.go | 44 +++++++++++++++------ 6 files changed, 130 insertions(+), 21 deletions(-) create mode 100644 internal/iplibrary/action_html.go diff --git a/internal/iplibrary/action_base.go b/internal/iplibrary/action_base.go index 5375e3d..13ac4e7 100644 --- a/internal/iplibrary/action_base.go +++ b/internal/iplibrary/action_base.go @@ -3,6 +3,7 @@ package iplibrary import ( "encoding/json" "github.com/iwind/TeaGo/maps" + "net/http" ) type BaseAction struct { @@ -12,6 +13,11 @@ func (this *BaseAction) Close() error { return nil } +// 处理HTTP请求 +func (this *BaseAction) DoHTTP(req *http.Request, resp http.ResponseWriter) (goNext bool, err error) { + return true, nil +} + func (this *BaseAction) convertParams(params maps.Map, ptr interface{}) error { data, err := json.Marshal(params) if err != nil { diff --git a/internal/iplibrary/action_html.go b/internal/iplibrary/action_html.go new file mode 100644 index 0000000..3d167f2 --- /dev/null +++ b/internal/iplibrary/action_html.go @@ -0,0 +1,55 @@ +package iplibrary + +import ( + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs" + "net/http" +) + +// HTML动作 +type HTMLAction struct { + BaseAction + + config *firewallconfigs.FirewallActionHTMLConfig +} + +// 获取新对象 +func NewHTMLAction() *HTMLAction { + return &HTMLAction{} +} + +// 初始化 +func (this *HTMLAction) Init(config *firewallconfigs.FirewallActionConfig) error { + this.config = &firewallconfigs.FirewallActionHTMLConfig{} + err := this.convertParams(config.Params, this.config) + if err != nil { + return err + } + return nil +} + +// 添加 +func (this *HTMLAction) AddItem(listType IPListType, item *pb.IPItem) error { + return nil +} + +// 删除 +func (this *HTMLAction) DeleteItem(listType IPListType, item *pb.IPItem) error { + return nil +} + +// 关闭 +func (this *HTMLAction) Close() error { + return nil +} + +// 处理HTTP请求 +func (this *HTMLAction) DoHTTP(req *http.Request, resp http.ResponseWriter) (goNext bool, err error) { + if this.config == nil { + goNext = true + return + } + resp.WriteHeader(http.StatusForbidden) // TODO改成可以配置 + _, _ = resp.Write([]byte(this.config.Content)) + return false, nil +} diff --git a/internal/iplibrary/action_interface.go b/internal/iplibrary/action_interface.go index 0279a82..bdd635a 100644 --- a/internal/iplibrary/action_interface.go +++ b/internal/iplibrary/action_interface.go @@ -3,6 +3,7 @@ package iplibrary import ( "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs" + "net/http" ) type ActionInterface interface { @@ -17,4 +18,7 @@ type ActionInterface interface { // 关闭 Close() error + + // 处理HTTP请求 + DoHTTP(req *http.Request, resp http.ResponseWriter) (goNext bool, err error) } diff --git a/internal/iplibrary/action_manager.go b/internal/iplibrary/action_manager.go index 93ed105..51aa2e5 100644 --- a/internal/iplibrary/action_manager.go +++ b/internal/iplibrary/action_manager.go @@ -60,12 +60,12 @@ func (this *ActionManager) UpdateActions(actions []*firewallconfigs.FirewallActi // 检查配置是否一致 oldConfigJSON, err := json.Marshal(this.configMap[newAction.Id]) if err != nil { - remotelogs.Error("IPLIBRARY/ACTION_MANAGER", "action "+strconv.FormatInt(newAction.Id, 10) + ", type:" + newAction.Type+": "+err.Error()) + remotelogs.Error("IPLIBRARY/ACTION_MANAGER", "action "+strconv.FormatInt(newAction.Id, 10)+", type:"+newAction.Type+": "+err.Error()) continue } newConfigJSON, err := json.Marshal(newAction) if err != nil { - remotelogs.Error("IPLIBRARY/ACTION_MANAGER", "action "+strconv.FormatInt(newAction.Id, 10) + ", type:" + newAction.Type+": "+err.Error()) + remotelogs.Error("IPLIBRARY/ACTION_MANAGER", "action "+strconv.FormatInt(newAction.Id, 10)+", type:"+newAction.Type+": "+err.Error()) continue } if bytes.Compare(newConfigJSON, oldConfigJSON) != 0 { @@ -75,7 +75,7 @@ func (this *ActionManager) UpdateActions(actions []*firewallconfigs.FirewallActi // 之所以要重新创建,是因为前后的动作类型可能有变化,完全重建可以避免不必要的麻烦 newInstance, err := this.createInstance(newAction) if err != nil { - remotelogs.Error("IPLIBRARY/ACTION_MANAGER", "reload action "+strconv.FormatInt(newAction.Id, 10) + ", type:" + newAction.Type+": "+err.Error()) + remotelogs.Error("IPLIBRARY/ACTION_MANAGER", "reload action "+strconv.FormatInt(newAction.Id, 10)+", type:"+newAction.Type+": "+err.Error()) continue } remotelogs.Println("IPLIBRARY/ACTION_MANAGER", "reloaded "+strconv.FormatInt(newAction.Id, 10)+", type:"+newAction.Type) @@ -85,7 +85,7 @@ func (this *ActionManager) UpdateActions(actions []*firewallconfigs.FirewallActi // 创建 instance, err := this.createInstance(newAction) if err != nil { - remotelogs.Error("IPLIBRARY/ACTION_MANAGER", "load new action "+strconv.FormatInt(newAction.Id, 10) + ", type:" + newAction.Type+": "+err.Error()) + remotelogs.Error("IPLIBRARY/ACTION_MANAGER", "load new action "+strconv.FormatInt(newAction.Id, 10)+", type:"+newAction.Type+": "+err.Error()) continue } remotelogs.Println("IPLIBRARY/ACTION_MANAGER", "loaded action "+strconv.FormatInt(newAction.Id, 10)+", type:"+newAction.Type) @@ -108,6 +108,13 @@ func (this *ActionManager) UpdateActions(actions []*firewallconfigs.FirewallActi } } +// 查找事件对应的动作 +func (this *ActionManager) FindEventActions(eventLevel string) []ActionInterface { + this.locker.Lock() + defer this.locker.Unlock() + return this.eventMap[eventLevel] +} + // 执行添加IP动作 func (this *ActionManager) AddItem(listType IPListType, item *pb.IPItem) { instances, ok := this.eventMap[item.EventLevel] @@ -147,6 +154,8 @@ func (this *ActionManager) createInstance(config *firewallconfigs.FirewallAction instance = NewScriptAction() case firewallconfigs.FirewallActionTypeHTTPAPI: instance = NewHTTPAPIAction() + case firewallconfigs.FirewallActionTypeHTML: + instance = NewHTMLAction() } if instance == nil { return nil, errors.New("can not create instance for type '" + config.Type + "'") diff --git a/internal/iplibrary/ip_list.go b/internal/iplibrary/ip_list.go index adfd2f2..4f04582 100644 --- a/internal/iplibrary/ip_list.go +++ b/internal/iplibrary/ip_list.go @@ -110,27 +110,40 @@ func (this *IPList) Contains(ip uint64) bool { } // 是否包含一组IP -func (this *IPList) ContainsIPStrings(ipStrings []string) bool { +func (this *IPList) ContainsIPStrings(ipStrings []string) (found bool, item *IPItem) { if len(ipStrings) == 0 { - return false + return } this.locker.RLock() if this.isAll { + itemIds := this.ipMap[0] + if len(itemIds) > 0 { + itemId := itemIds[0] + item = this.itemsMap[itemId] + } + this.locker.RUnlock() - return true + found = true + return } for _, ipString := range ipStrings { if len(ipString) == 0 { continue } - _, ok := this.ipMap[utils.IP2Long(ipString)] + itemIds, ok := this.ipMap[utils.IP2Long(ipString)] if ok { + if len(itemIds) > 0 { + itemId := itemIds[0] + item = this.itemsMap[itemId] + } + this.locker.RUnlock() - return true + found = true + return } } this.locker.RUnlock() - return false + return } // 在不加锁的情况下删除某个Item diff --git a/internal/nodes/http_request_waf.go b/internal/nodes/http_request_waf.go index 9d8f68a..57795bb 100644 --- a/internal/nodes/http_request_waf.go +++ b/internal/nodes/http_request_waf.go @@ -49,25 +49,47 @@ func (this *HTTPRequest) checkWAFRequest(firewallPolicy *firewallconfigs.HTTPFir inbound := firewallPolicy.Inbound if inbound.AllowListRef != nil && inbound.AllowListRef.IsOn && inbound.AllowListRef.ListId > 0 { list := iplibrary.SharedIPListManager.FindList(inbound.AllowListRef.ListId) - if list != nil && list.ContainsIPStrings(remoteAddrs) { - breakChecking = true - return + if list != nil { + found, _ := list.ContainsIPStrings(remoteAddrs) + if found { + breakChecking = true + return + } } } // 检查IP黑名单 if inbound.DenyListRef != nil && inbound.DenyListRef.IsOn && inbound.DenyListRef.ListId > 0 { list := iplibrary.SharedIPListManager.FindList(inbound.DenyListRef.ListId) - if list != nil && list.ContainsIPStrings(remoteAddrs) { - // TODO 可以配置对封禁的处理方式等 - // TODO 需要记录日志信息 - this.writer.WriteHeader(http.StatusForbidden) - this.writer.Close() + if list != nil { + found, item := list.ContainsIPStrings(remoteAddrs) + if found { + // 触发事件 + if item != nil && len(item.EventLevel) > 0 { + actions := iplibrary.SharedActionManager.FindEventActions(item.EventLevel) + for _, action := range actions { + goNext, err := action.DoHTTP(this.RawReq, this.RawWriter) + if err != nil { + remotelogs.Error("REQUEST", "do action '"+err.Error()+"' failed: "+err.Error()) + return true, false + } + if !goNext { + this.disableLog = true + return true, false + } + } + } - // 停止日志 - this.disableLog = true + // TODO 需要记录日志信息 - return true, false + this.writer.WriteHeader(http.StatusForbidden) + this.writer.Close() + + // 停止日志 + this.disableLog = true + + return true, false + } } }