From ecd16cba0ea3ab12b6522ded08a8e4a56780e9ca Mon Sep 17 00:00:00 2001 From: GoEdgeLab Date: Sun, 3 Jan 2021 20:18:21 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=A8=E6=88=B7=E7=AB=AF=E5=8F=AF=E4=BB=A5?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0WAF=20=E9=BB=91=E7=99=BD=E5=90=8D=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/errors/detailed_error.go | 21 +++ pkg/errors/error.go | 66 +++++++++ pkg/errors/error_test.go | 22 +++ pkg/rpc/dao/http_firewall_policy_dao.go | 12 +- pkg/rpc/dao/http_web_dao.go | 94 +++++++++++++ pkg/rpc/dao/ip_list_dao.go | 128 ++++++++++++++++++ .../http_firewall_inbound_config.go | 4 +- pkg/serverconfigs/http_web_config.go | 48 ++++--- 8 files changed, 367 insertions(+), 28 deletions(-) create mode 100644 pkg/errors/detailed_error.go create mode 100644 pkg/errors/error.go create mode 100644 pkg/errors/error_test.go create mode 100644 pkg/rpc/dao/http_web_dao.go create mode 100644 pkg/rpc/dao/ip_list_dao.go diff --git a/pkg/errors/detailed_error.go b/pkg/errors/detailed_error.go new file mode 100644 index 0000000..d2e12ed --- /dev/null +++ b/pkg/errors/detailed_error.go @@ -0,0 +1,21 @@ +package errors + +type DetailedError struct { + msg string + code string +} + +func (this *DetailedError) Error() string { + return this.msg +} + +func (this *DetailedError) Code() string { + return this.code +} + +func NewDetailedError(code string, error string) *DetailedError { + return &DetailedError{ + msg: error, + code: code, + } +} diff --git a/pkg/errors/error.go b/pkg/errors/error.go new file mode 100644 index 0000000..c873fec --- /dev/null +++ b/pkg/errors/error.go @@ -0,0 +1,66 @@ +package errors + +import ( + "errors" + "github.com/iwind/TeaGo/Tea" + "path/filepath" + "runtime" + "strconv" +) + +type errorObj struct { + err error + file string + line int + funcName string +} + +func (this *errorObj) Error() string { + // 在非测试环境下,我们不提示详细的行数等信息 + if !Tea.IsTesting() { + return this.err.Error() + } + + s := this.err.Error() + "\n " + this.file + if len(this.funcName) > 0 { + s += ":" + this.funcName + "()" + } + s += ":" + strconv.Itoa(this.line) + return s +} + +// 新错误 +func New(errText string) error { + ptr, file, line, ok := runtime.Caller(1) + funcName := "" + if ok { + frame, _ := runtime.CallersFrames([]uintptr{ptr}).Next() + funcName = filepath.Base(frame.Function) + } + return &errorObj{ + err: errors.New(errText), + file: file, + line: line, + funcName: funcName, + } +} + +// 包装已有错误 +func Wrap(err error) error { + if err == nil { + return nil + } + + ptr, file, line, ok := runtime.Caller(1) + funcName := "" + if ok { + frame, _ := runtime.CallersFrames([]uintptr{ptr}).Next() + funcName = filepath.Base(frame.Function) + } + return &errorObj{ + err: err, + file: file, + line: line, + funcName: funcName, + } +} diff --git a/pkg/errors/error_test.go b/pkg/errors/error_test.go new file mode 100644 index 0000000..b288d27 --- /dev/null +++ b/pkg/errors/error_test.go @@ -0,0 +1,22 @@ +package errors + +import ( + "errors" + "testing" +) + +func TestNew(t *testing.T) { + t.Log(New("hello")) + t.Log(Wrap(errors.New("hello"))) + t.Log(testError1()) + t.Log(Wrap(testError1())) + t.Log(Wrap(testError2())) +} + +func testError1() error { + return New("test error1") +} + +func testError2() error { + return Wrap(testError1()) +} diff --git a/pkg/rpc/dao/http_firewall_policy_dao.go b/pkg/rpc/dao/http_firewall_policy_dao.go index e1aa4b4..5aa9308 100644 --- a/pkg/rpc/dao/http_firewall_policy_dao.go +++ b/pkg/rpc/dao/http_firewall_policy_dao.go @@ -78,7 +78,7 @@ func (this *HTTPFirewallPolicyDAO) FindEnabledPolicyWhiteIPListId(ctx context.Co if config.Inbound == nil { config.Inbound = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true} } - if config.Inbound.WhiteListRef == nil || config.Inbound.WhiteListRef.ListId == 0 { + if config.Inbound.AllowListRef == nil || config.Inbound.AllowListRef.ListId == 0 { createResp, err := this.RPC().IPListRPC().CreateIPList(ctx, &pb.CreateIPListRequest{ Type: "white", Name: "白名单", @@ -89,7 +89,7 @@ func (this *HTTPFirewallPolicyDAO) FindEnabledPolicyWhiteIPListId(ctx context.Co return 0, err } listId := createResp.IpListId - config.Inbound.WhiteListRef = &ipconfigs.IPListRef{ + config.Inbound.AllowListRef = &ipconfigs.IPListRef{ IsOn: true, ListId: listId, } @@ -107,7 +107,7 @@ func (this *HTTPFirewallPolicyDAO) FindEnabledPolicyWhiteIPListId(ctx context.Co return listId, nil } - return config.Inbound.WhiteListRef.ListId, nil + return config.Inbound.AllowListRef.ListId, nil } // 查找WAF的黑名单 @@ -122,7 +122,7 @@ func (this *HTTPFirewallPolicyDAO) FindEnabledPolicyBlackIPListId(ctx context.Co if config.Inbound == nil { config.Inbound = &firewallconfigs.HTTPFirewallInboundConfig{IsOn: true} } - if config.Inbound.BlackListRef == nil || config.Inbound.BlackListRef.ListId == 0 { + if config.Inbound.DenyListRef == nil || config.Inbound.DenyListRef.ListId == 0 { createResp, err := this.RPC().IPListRPC().CreateIPList(ctx, &pb.CreateIPListRequest{ Type: "black", Name: "黑名单", @@ -133,7 +133,7 @@ func (this *HTTPFirewallPolicyDAO) FindEnabledPolicyBlackIPListId(ctx context.Co return 0, err } listId := createResp.IpListId - config.Inbound.BlackListRef = &ipconfigs.IPListRef{ + config.Inbound.DenyListRef = &ipconfigs.IPListRef{ IsOn: true, ListId: listId, } @@ -151,7 +151,7 @@ func (this *HTTPFirewallPolicyDAO) FindEnabledPolicyBlackIPListId(ctx context.Co return listId, nil } - return config.Inbound.BlackListRef.ListId, nil + return config.Inbound.DenyListRef.ListId, nil } // 根据服务Id查找WAF策略 diff --git a/pkg/rpc/dao/http_web_dao.go b/pkg/rpc/dao/http_web_dao.go new file mode 100644 index 0000000..2e016c9 --- /dev/null +++ b/pkg/rpc/dao/http_web_dao.go @@ -0,0 +1,94 @@ +package dao + +import ( + "context" + "encoding/json" + "github.com/TeaOSLab/EdgeCommon/pkg/errors" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs" +) + +var SharedHTTPWebDAO = new(HTTPWebDAO) + +type HTTPWebDAO struct { + BaseDAO +} + +// 根据ServerId查找Web配置 +func (this *HTTPWebDAO) FindWebConfigWithServerId(ctx context.Context, serverId int64) (*serverconfigs.HTTPWebConfig, error) { + resp, err := this.RPC().ServerRPC().FindAndInitServerWebConfig(ctx, &pb.FindAndInitServerWebConfigRequest{ServerId: serverId}) + if err != nil { + return nil, err + } + config := &serverconfigs.HTTPWebConfig{} + err = json.Unmarshal(resp.WebJSON, config) + if err != nil { + return nil, err + } + return config, nil +} + +// 根据LocationId查找Web配置 +func (this *HTTPWebDAO) FindWebConfigWithLocationId(ctx context.Context, locationId int64) (*serverconfigs.HTTPWebConfig, error) { + resp, err := this.RPC().HTTPLocationRPC().FindAndInitHTTPLocationWebConfig(ctx, &pb.FindAndInitHTTPLocationWebConfigRequest{LocationId: locationId}) + if err != nil { + return nil, err + } + config := &serverconfigs.HTTPWebConfig{} + err = json.Unmarshal(resp.WebJSON, config) + if err != nil { + return nil, err + } + return config, nil +} + +// 根据WebId查找Web配置 +func (this *HTTPWebDAO) FindWebConfigWithId(ctx context.Context, webId int64) (*serverconfigs.HTTPWebConfig, error) { + resp, err := this.RPC().HTTPWebRPC().FindEnabledHTTPWebConfig(ctx, &pb.FindEnabledHTTPWebConfigRequest{WebId: webId}) + if err != nil { + return nil, err + } + config := &serverconfigs.HTTPWebConfig{} + err = json.Unmarshal(resp.WebJSON, config) + if err != nil { + return nil, err + } + return config, nil +} + +// 初始化防火墙设置 +func (this *HTTPWebDAO) InitHTTPFirewallPolicy(ctx context.Context, webId int64) (int64, error) { + // 创建FirewallPolicy + firewallPolicyIdResp, err := this.RPC().HTTPFirewallPolicyRPC().CreateHTTPFirewallPolicy(ctx, &pb.CreateHTTPFirewallPolicyRequest{ + IsOn: true, + Name: "用户自定义", + Description: "", + HttpFirewallGroupCodes: nil, + }) + if err != nil { + return 0, errors.Wrap(err) + } + + policyId := firewallPolicyIdResp.HttpFirewallPolicyId + + firewallRef := &firewallconfigs.HTTPFirewallRef{ + IsPrior: false, + IsOn: true, + FirewallPolicyId: policyId, + } + firewallRefJSON, err := json.Marshal(firewallRef) + if err != nil { + return 0, errors.Wrap(err) + } + + _, err = this.RPC().HTTPWebRPC().UpdateHTTPWebFirewall(ctx, &pb.UpdateHTTPWebFirewallRequest{ + WebId: webId, + FirewallJSON: firewallRefJSON, + }) + if err != nil { + return 0, errors.Wrap(err) + } + + return policyId, nil +} diff --git a/pkg/rpc/dao/ip_list_dao.go b/pkg/rpc/dao/ip_list_dao.go new file mode 100644 index 0000000..fda620d --- /dev/null +++ b/pkg/rpc/dao/ip_list_dao.go @@ -0,0 +1,128 @@ +package dao + +import ( + "context" + "encoding/json" + "github.com/TeaOSLab/EdgeCommon/pkg/errors" + "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ipconfigs" +) + +var SharedIPListDAO = new(IPListDAO) + +type IPListDAO struct { + BaseDAO +} + +// 查找服务的允许IP列表 +func (this *IPListDAO) FindAllowIPListIdWithServerId(ctx context.Context, serverId int64) (int64, error) { + webConfig, err := SharedHTTPWebDAO.FindWebConfigWithServerId(ctx, serverId) + if err != nil { + return 0, err + } + if webConfig == nil { + return 0, nil + } + if webConfig.FirewallPolicy == nil || webConfig.FirewallPolicy.Inbound == nil || webConfig.FirewallPolicy.Inbound.AllowListRef == nil { + return 0, nil + } + return webConfig.FirewallPolicy.Inbound.AllowListRef.ListId, nil +} + +// 查找服务的禁止IP列表 +func (this *IPListDAO) FindDenyIPListIdWithServerId(ctx context.Context, serverId int64) (int64, error) { + webConfig, err := SharedHTTPWebDAO.FindWebConfigWithServerId(ctx, serverId) + if err != nil { + return 0, err + } + if webConfig == nil { + return 0, nil + } + if webConfig.FirewallPolicy == nil || webConfig.FirewallPolicy.Inbound == nil || webConfig.FirewallPolicy.Inbound.DenyListRef == nil { + return 0, nil + } + return webConfig.FirewallPolicy.Inbound.DenyListRef.ListId, nil +} + +// 为服务创建IP名单 +func (this *IPListDAO) CreateIPListForServerId(ctx context.Context, serverId int64, listType string) (int64, error) { + webConfig, err := SharedHTTPWebDAO.FindWebConfigWithServerId(ctx, serverId) + if err != nil { + return 0, err + } + if webConfig == nil { + return 0, nil + } + if webConfig.FirewallPolicy == nil || webConfig.FirewallPolicy.Id == 0 { + _, err = SharedHTTPWebDAO.InitHTTPFirewallPolicy(ctx, webConfig.Id) + if err != nil { + return 0, errors.Wrap(err) + } + webConfig, err = SharedHTTPWebDAO.FindWebConfigWithServerId(ctx, serverId) + if err != nil { + return 0, err + } + if webConfig == nil { + return 0, nil + } + if webConfig.FirewallPolicy == nil { + return 0, nil + } + } + + inbound := webConfig.FirewallPolicy.Inbound + if inbound == nil { + inbound = &firewallconfigs.HTTPFirewallInboundConfig{ + IsOn: true, + } + } + if listType == "white" { + if inbound.AllowListRef == nil { + inbound.AllowListRef = &ipconfigs.IPListRef{ + IsOn: true, + } + } + if inbound.AllowListRef.ListId > 0 { + return inbound.AllowListRef.ListId, nil + } + } else if listType == "black" { + if inbound.DenyListRef == nil { + inbound.DenyListRef = &ipconfigs.IPListRef{ + IsOn: true, + } + } + if inbound.DenyListRef.ListId > 0 { + return inbound.DenyListRef.ListId, nil + } + } + + ipListResp, err := this.RPC().IPListRPC().CreateIPList(ctx, &pb.CreateIPListRequest{ + Type: listType, + Name: "IP名单", + Code: listType, + TimeoutJSON: nil, + }) + if err != nil { + return 0, errors.Wrap(err) + } + + if listType == "white" { + inbound.AllowListRef.ListId = ipListResp.IpListId + } else if listType == "black" { + inbound.DenyListRef.ListId = ipListResp.IpListId + } + inboundJSON, err := json.Marshal(inbound) + if err != nil { + return 0, errors.Wrap(err) + } + _, err = this.RPC().HTTPFirewallPolicyRPC().UpdateHTTPFirewallInboundConfig(ctx, &pb.UpdateHTTPFirewallInboundConfigRequest{ + HttpFirewallPolicyId: webConfig.FirewallPolicy.Id, + InboundJSON: inboundJSON, + }) + if err != nil { + return 0, errors.Wrap(err) + } + + return ipListResp.IpListId, nil +} diff --git a/pkg/serverconfigs/firewallconfigs/http_firewall_inbound_config.go b/pkg/serverconfigs/firewallconfigs/http_firewall_inbound_config.go index fca46e0..b520793 100644 --- a/pkg/serverconfigs/firewallconfigs/http_firewall_inbound_config.go +++ b/pkg/serverconfigs/firewallconfigs/http_firewall_inbound_config.go @@ -11,8 +11,8 @@ type HTTPFirewallInboundConfig struct { Region *HTTPFirewallRegionConfig `yaml:"region" json:"region"` // IP名单 - WhiteListRef *ipconfigs.IPListRef `yaml:"whiteListRef" json:"whiteListRef"` - BlackListRef *ipconfigs.IPListRef `yaml:"blackListRef" json:"blackListRef"` + AllowListRef *ipconfigs.IPListRef `yaml:"whiteListRef" json:"whiteListRef"` + DenyListRef *ipconfigs.IPListRef `yaml:"blackListRef" json:"blackListRef"` GreyListRef *ipconfigs.IPListRef `yaml:"greyListRef" json:"greyListRef"` } diff --git a/pkg/serverconfigs/http_web_config.go b/pkg/serverconfigs/http_web_config.go index 792d9b2..ae6ffda 100644 --- a/pkg/serverconfigs/http_web_config.go +++ b/pkg/serverconfigs/http_web_config.go @@ -6,26 +6,27 @@ import ( ) type HTTPWebConfig struct { - Id int64 `yaml:"id" json:"id"` // ID - IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用 - Locations []*HTTPLocationConfig `yaml:"locations" json:"locations"` // 路径规则 TODO - LocationRefs []*HTTPLocationRef `yaml:"locationRefs" json:"locationRefs"` // 路径规则应用 - GzipRef *HTTPGzipRef `yaml:"gzipRef" json:"gzipRef"` // Gzip引用 - Gzip *HTTPGzipConfig `yaml:"gzip" json:"gzip"` // Gzip配置 - Charset *HTTPCharsetConfig `yaml:"charset" json:"charset"` // 字符编码 - Shutdown *HTTPShutdownConfig `yaml:"shutdown" json:"shutdown"` // 临时关闭配置 - Pages []*HTTPPageConfig `yaml:"pages" json:"pages"` // 特殊页面配置 - RedirectToHttps *HTTPRedirectToHTTPSConfig `yaml:"redirectToHTTPS" json:"redirectToHTTPS"` // 是否自动跳转到Https - Root *HTTPRootConfig `yaml:"root" json:"root"` // 资源根目录 TODO - MaxRequestBodySize string `yaml:"maxRequestBodySize" json:"maxRequestBodySize"` // 请求body最大尺寸 TODO 需要实现 - AccessLogRef *HTTPAccessLogRef `yaml:"accessLog" json:"accessLog"` // 访问日志配置 - StatRef *HTTPStatRef `yaml:"statRef" json:"statRef"` // 统计配置 - Cache *HTTPCacheConfig `yaml:"cache" json:"cache"` // 缓存配置 - FirewallRef *firewallconfigs.HTTPFirewallRef `yaml:"firewallRef" json:"firewallRef"` // 防火墙设置 - WebsocketRef *HTTPWebsocketRef `yaml:"websocketRef" json:"websocketRef"` // Websocket应用配置 - Websocket *HTTPWebsocketConfig `yaml:"websocket" json:"websocket"` // Websocket配置 - RewriteRefs []*HTTPRewriteRef `yaml:"rewriteRefs" json:"rewriteRefs"` // 重写规则配置 - RewriteRules []*HTTPRewriteRule `yaml:"rewriteRules" json:"rewriteRules"` // 重写规则 + Id int64 `yaml:"id" json:"id"` // ID + IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用 + Locations []*HTTPLocationConfig `yaml:"locations" json:"locations"` // 路径规则 TODO + LocationRefs []*HTTPLocationRef `yaml:"locationRefs" json:"locationRefs"` // 路径规则应用 + GzipRef *HTTPGzipRef `yaml:"gzipRef" json:"gzipRef"` // Gzip引用 + Gzip *HTTPGzipConfig `yaml:"gzip" json:"gzip"` // Gzip配置 + Charset *HTTPCharsetConfig `yaml:"charset" json:"charset"` // 字符编码 + Shutdown *HTTPShutdownConfig `yaml:"shutdown" json:"shutdown"` // 临时关闭配置 + Pages []*HTTPPageConfig `yaml:"pages" json:"pages"` // 特殊页面配置 + RedirectToHttps *HTTPRedirectToHTTPSConfig `yaml:"redirectToHTTPS" json:"redirectToHTTPS"` // 是否自动跳转到Https + Root *HTTPRootConfig `yaml:"root" json:"root"` // 资源根目录 TODO + MaxRequestBodySize string `yaml:"maxRequestBodySize" json:"maxRequestBodySize"` // 请求body最大尺寸 TODO 需要实现 + AccessLogRef *HTTPAccessLogRef `yaml:"accessLog" json:"accessLog"` // 访问日志配置 + StatRef *HTTPStatRef `yaml:"statRef" json:"statRef"` // 统计配置 + Cache *HTTPCacheConfig `yaml:"cache" json:"cache"` // 缓存配置 + FirewallRef *firewallconfigs.HTTPFirewallRef `yaml:"firewallRef" json:"firewallRef"` // 防火墙设置 + FirewallPolicy *firewallconfigs.HTTPFirewallPolicy `yaml:"firewallPolicy" json:"firewallPolicy"` // 防火墙策略 + WebsocketRef *HTTPWebsocketRef `yaml:"websocketRef" json:"websocketRef"` // Websocket应用配置 + Websocket *HTTPWebsocketConfig `yaml:"websocket" json:"websocket"` // Websocket配置 + RewriteRefs []*HTTPRewriteRef `yaml:"rewriteRefs" json:"rewriteRefs"` // 重写规则配置 + RewriteRules []*HTTPRewriteRule `yaml:"rewriteRules" json:"rewriteRules"` // 重写规则 RequestHeaderPolicyRef *shared.HTTPHeaderPolicyRef `yaml:"requestHeaderPolicyRef" json:"requestHeaderPolicyRef"` // 请求Header RequestHeaderPolicy *shared.HTTPHeaderPolicy `yaml:"requestHeaderPolicy" json:"requestHeaderPolicy"` // 请求Header策略 @@ -128,6 +129,13 @@ func (this *HTTPWebConfig) Init() error { return err } } + if this.FirewallPolicy != nil { + err := this.FirewallPolicy.Init() + if err != nil { + return err + } + } + // websocket if this.WebsocketRef != nil { err := this.WebsocketRef.Init()