实现WAF策略部分功能
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallAllowAction struct {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package firewallconfigs
|
||||
|
||||
// url client configure
|
||||
type HTTPFirewallBlockAction struct {
|
||||
StatusCode int `yaml:"statusCode" json:"statusCode"`
|
||||
Body string `yaml:"body" json:"body"` // supports HTML
|
||||
URL string `yaml:"url" json:"url"`
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallCaptchaAction struct {
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package firewallconfigs
|
||||
|
||||
import "reflect"
|
||||
|
||||
// action definition
|
||||
type HTTPFirewallActionDefinition struct {
|
||||
Name string
|
||||
Code HTTPFirewallActionString
|
||||
Description string
|
||||
Type reflect.Type
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallGoGroupAction struct {
|
||||
GroupId string `yaml:"groupId" json:"groupId"`
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallGoSetAction struct {
|
||||
GroupId string `yaml:"groupId" json:"groupId"`
|
||||
SetId string `yaml:"setId" json:"setId"`
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package firewallconfigs
|
||||
|
||||
type Action struct {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallLogAction struct {
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallActionString = string
|
||||
|
||||
const (
|
||||
HTTPFirewallActionLog = "log" // allow and log
|
||||
HTTPFirewallActionBlock = "block" // block
|
||||
HTTPFirewallActionCaptcha = "captcha" // block and show captcha
|
||||
HTTPFirewallActionAllow = "allow" // allow
|
||||
HTTPFirewallActionGoGroup = "go_group" // go to next rule group
|
||||
HTTPFirewallActionGoSet = "go_set" // go to next rule set
|
||||
)
|
||||
@@ -0,0 +1,43 @@
|
||||
package firewallconfigs
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var AllActions = []*HTTPFirewallActionDefinition{
|
||||
{
|
||||
Name: "阻止",
|
||||
Code: HTTPFirewallActionBlock,
|
||||
},
|
||||
{
|
||||
Name: "允许通过",
|
||||
Code: HTTPFirewallActionAllow,
|
||||
},
|
||||
{
|
||||
Name: "允许并记录日志",
|
||||
Code: HTTPFirewallActionLog,
|
||||
},
|
||||
{
|
||||
Name: "Captcha验证码",
|
||||
Code: HTTPFirewallActionCaptcha,
|
||||
},
|
||||
{
|
||||
Name: "跳到下一个规则分组",
|
||||
Code: HTTPFirewallActionGoGroup,
|
||||
Type: reflect.TypeOf(new(HTTPFirewallGoGroupAction)).Elem(),
|
||||
},
|
||||
{
|
||||
Name: "跳到下一个规则集",
|
||||
Code: HTTPFirewallActionGoSet,
|
||||
Type: reflect.TypeOf(new(HTTPFirewallGoSetAction)).Elem(),
|
||||
},
|
||||
}
|
||||
|
||||
func FindActionName(action HTTPFirewallActionString) string {
|
||||
for _, def := range AllActions {
|
||||
if def.Code == action {
|
||||
return def.Name
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package firewallconfigs
|
||||
@@ -0,0 +1,28 @@
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallInboundConfig struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
GroupRefs []*HTTPFirewallRuleGroupRef `yaml:"groupRefs" json:"groupRefs"`
|
||||
Groups []*HTTPFirewallRuleGroup `yaml:"groups" json:"groups"`
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (this *HTTPFirewallInboundConfig) Init() error {
|
||||
for _, group := range this.Groups {
|
||||
err := group.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 根据Code查找Group
|
||||
func (this *HTTPFirewallInboundConfig) FindGroupWithCode(code string) *HTTPFirewallRuleGroup {
|
||||
for _, group := range this.Groups {
|
||||
if group.Code == code {
|
||||
return group
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallOutboundConfig struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
GroupRefs []*HTTPFirewallRuleGroupRef `yaml:"groupRefs" json:"groupRefs"`
|
||||
Groups []*HTTPFirewallRuleGroup `yaml:"groups" json:"groups"`
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (this *HTTPFirewallOutboundConfig) Init() error {
|
||||
for _, group := range this.Groups {
|
||||
err := group.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 根据Code查找Group
|
||||
func (this *HTTPFirewallOutboundConfig) FindGroupWithCode(code string) *HTTPFirewallRuleGroup {
|
||||
for _, group := range this.Groups {
|
||||
if group.Code == code {
|
||||
return group
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
51
pkg/serverconfigs/firewallconfigs/http_firewall_policy.go
Normal file
51
pkg/serverconfigs/firewallconfigs/http_firewall_policy.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package firewallconfigs
|
||||
|
||||
// 防火墙策略
|
||||
type HTTPFirewallPolicy struct {
|
||||
Id int64 `yaml:"id" json:"id"`
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Description string `yaml:"description" json:"description"`
|
||||
Inbound *HTTPFirewallInboundConfig `yaml:"inbound" json:"inbound"`
|
||||
Outbound *HTTPFirewallOutboundConfig `yaml:"outbound" json:"outbound"`
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (this *HTTPFirewallPolicy) Init() error {
|
||||
if this.Inbound != nil {
|
||||
err := this.Inbound.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if this.Outbound != nil {
|
||||
err := this.Outbound.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取所有分组
|
||||
func (this *HTTPFirewallPolicy) AllRuleGroups() []*HTTPFirewallRuleGroup {
|
||||
result := []*HTTPFirewallRuleGroup{}
|
||||
if this.Inbound != nil {
|
||||
result = append(result, this.Inbound.Groups...)
|
||||
}
|
||||
if this.Outbound != nil {
|
||||
result = append(result, this.Outbound.Groups...)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// 根据代号获取分组
|
||||
func (this *HTTPFirewallPolicy) FindRuleGroupWithCode(code string) *HTTPFirewallRuleGroup {
|
||||
for _, g := range this.AllRuleGroups() {
|
||||
if g.Code == code {
|
||||
return g
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package serverconfigs
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallRef struct {
|
||||
IsPrior bool `yaml:"isPrior" json:"isPrior"`
|
||||
16
pkg/serverconfigs/firewallconfigs/http_firewall_rule.go
Normal file
16
pkg/serverconfigs/firewallconfigs/http_firewall_rule.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallRule struct {
|
||||
Id int64 `yaml:"id" json:"id"`
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
Param string `yaml:"param" json:"param"`
|
||||
Operator string `yaml:"operator" json:"operator"`
|
||||
Value string `yaml:"value" json:"value"`
|
||||
IsCaseInsensitive bool `yaml:"isCaseInsensitive" json:"isCaseInsensitive"`
|
||||
CheckpointOptions map[string]interface{} `yaml:"checkpointOptions" json:"checkpointOptions"`
|
||||
Description string `yaml:"description" json:"description"`
|
||||
}
|
||||
|
||||
func (this *HTTPFirewallRule) Init() error {
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package firewallconfigs
|
||||
|
||||
// 规则组
|
||||
type HTTPFirewallRuleGroup struct {
|
||||
Id int64 `yaml:"id" json:"id"`
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Description string `yaml:"description" json:"description"`
|
||||
Code string `yaml:"code" json:"code"`
|
||||
SetRefs []*HTTPFirewallRuleSetRef `yaml:"setRefs" json:"setRefs"`
|
||||
Sets []*HTTPFirewallRuleSet `yaml:"sets" json:"sets"`
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (this *HTTPFirewallRuleGroup) Init() error {
|
||||
for _, set := range this.Sets {
|
||||
err := set.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 添加规则集
|
||||
func (this *HTTPFirewallRuleGroup) AddRuleSet(ruleSet *HTTPFirewallRuleSet) {
|
||||
this.Sets = append(this.Sets, ruleSet)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallRuleGroupRef struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
GroupId int64 `yaml:"groupId" json:"groupId"`
|
||||
}
|
||||
219
pkg/serverconfigs/firewallconfigs/http_firewall_rule_operator.go
Normal file
219
pkg/serverconfigs/firewallconfigs/http_firewall_rule_operator.go
Normal file
@@ -0,0 +1,219 @@
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallRuleOperator = string
|
||||
type HTTPFirewallRuleCaseInsensitive = string
|
||||
|
||||
const (
|
||||
HTTPFirewallRuleOperatorGt HTTPFirewallRuleOperator = "gt"
|
||||
HTTPFirewallRuleOperatorGte HTTPFirewallRuleOperator = "gte"
|
||||
HTTPFirewallRuleOperatorLt HTTPFirewallRuleOperator = "lt"
|
||||
HTTPFirewallRuleOperatorLte HTTPFirewallRuleOperator = "lte"
|
||||
HTTPFirewallRuleOperatorEq HTTPFirewallRuleOperator = "eq"
|
||||
HTTPFirewallRuleOperatorNeq HTTPFirewallRuleOperator = "neq"
|
||||
HTTPFirewallRuleOperatorEqString HTTPFirewallRuleOperator = "eq string"
|
||||
HTTPFirewallRuleOperatorNeqString HTTPFirewallRuleOperator = "neq string"
|
||||
HTTPFirewallRuleOperatorMatch HTTPFirewallRuleOperator = "match"
|
||||
HTTPFirewallRuleOperatorNotMatch HTTPFirewallRuleOperator = "not match"
|
||||
HTTPFirewallRuleOperatorContains HTTPFirewallRuleOperator = "contains"
|
||||
HTTPFirewallRuleOperatorNotContains HTTPFirewallRuleOperator = "not contains"
|
||||
HTTPFirewallRuleOperatorPrefix HTTPFirewallRuleOperator = "prefix"
|
||||
HTTPFirewallRuleOperatorSuffix HTTPFirewallRuleOperator = "suffix"
|
||||
HTTPFirewallRuleOperatorHasKey HTTPFirewallRuleOperator = "has key" // has key in slice or map
|
||||
HTTPFirewallRuleOperatorVersionGt HTTPFirewallRuleOperator = "version gt"
|
||||
HTTPFirewallRuleOperatorVersionLt HTTPFirewallRuleOperator = "version lt"
|
||||
HTTPFirewallRuleOperatorVersionRange HTTPFirewallRuleOperator = "version range"
|
||||
|
||||
// ip
|
||||
HTTPFirewallRuleOperatorEqIP HTTPFirewallRuleOperator = "eq ip"
|
||||
HTTPFirewallRuleOperatorGtIP HTTPFirewallRuleOperator = "gt ip"
|
||||
HTTPFirewallRuleOperatorGteIP HTTPFirewallRuleOperator = "gte ip"
|
||||
HTTPFirewallRuleOperatorLtIP HTTPFirewallRuleOperator = "lt ip"
|
||||
HTTPFirewallRuleOperatorLteIP HTTPFirewallRuleOperator = "lte ip"
|
||||
HTTPFirewallRuleOperatorIPRange HTTPFirewallRuleOperator = "ip range"
|
||||
HTTPFirewallRuleOperatorNotIPRange HTTPFirewallRuleOperator = "not ip range"
|
||||
HTTPFirewallRuleOperatorIPMod10 HTTPFirewallRuleOperator = "ip mod 10"
|
||||
HTTPFirewallRuleOperatorIPMod100 HTTPFirewallRuleOperator = "ip mod 100"
|
||||
HTTPFirewallRuleOperatorIPMod HTTPFirewallRuleOperator = "ip mod"
|
||||
|
||||
HTTPFirewallRuleCaseInsensitiveNone = "none"
|
||||
HTTPFirewallRuleCaseInsensitiveYes = "yes"
|
||||
HTTPFirewallRuleCaseInsensitiveNo = "no"
|
||||
)
|
||||
|
||||
type RuleOperatorDefinition struct {
|
||||
Name string
|
||||
Code string
|
||||
Description string
|
||||
CaseInsensitive HTTPFirewallRuleCaseInsensitive // default caseInsensitive setting
|
||||
}
|
||||
|
||||
var AllRuleOperators = []*RuleOperatorDefinition{
|
||||
{
|
||||
Name: "数值大于",
|
||||
Code: HTTPFirewallRuleOperatorGt,
|
||||
Description: "使用数值对比大于",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNone,
|
||||
},
|
||||
{
|
||||
Name: "数值大于等于",
|
||||
Code: HTTPFirewallRuleOperatorGte,
|
||||
Description: "使用数值对比大于等于",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNone,
|
||||
},
|
||||
{
|
||||
Name: "数值小于",
|
||||
Code: HTTPFirewallRuleOperatorLt,
|
||||
Description: "使用数值对比小于",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNone,
|
||||
},
|
||||
{
|
||||
Name: "数值小于等于",
|
||||
Code: HTTPFirewallRuleOperatorLte,
|
||||
Description: "使用数值对比小于等于",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNone,
|
||||
},
|
||||
{
|
||||
Name: "数值等于",
|
||||
Code: HTTPFirewallRuleOperatorEq,
|
||||
Description: "使用数值对比等于",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNone,
|
||||
},
|
||||
{
|
||||
Name: "数值不等于",
|
||||
Code: HTTPFirewallRuleOperatorNeq,
|
||||
Description: "使用数值对比不等于",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNone,
|
||||
},
|
||||
{
|
||||
Name: "字符串等于",
|
||||
Code: HTTPFirewallRuleOperatorEqString,
|
||||
Description: "使用字符串对比等于",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "字符串不等于",
|
||||
Code: HTTPFirewallRuleOperatorNeqString,
|
||||
Description: "使用字符串对比不等于",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "正则匹配",
|
||||
Code: HTTPFirewallRuleOperatorMatch,
|
||||
Description: "使用正则表达式匹配,在头部使用(?i)表示不区分大小写,<a href=\"http://teaos.cn/doc/regexp/Regexp.md\" target=\"_blank\">正则表达式语法 »</a>",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveYes,
|
||||
},
|
||||
{
|
||||
Name: "正则不匹配",
|
||||
Code: HTTPFirewallRuleOperatorNotMatch,
|
||||
Description: "使用正则表达式不匹配,在头部使用(?i)表示不区分大小写,<a href=\"http://teaos.cn/doc/regexp/Regexp.md\" target=\"_blank\">正则表达式语法 »</a>",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveYes,
|
||||
},
|
||||
{
|
||||
Name: "包含字符串",
|
||||
Code: HTTPFirewallRuleOperatorContains,
|
||||
Description: "包含某个字符串",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "不包含字符串",
|
||||
Code: HTTPFirewallRuleOperatorNotContains,
|
||||
Description: "不包含某个字符串",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "包含前缀",
|
||||
Code: HTTPFirewallRuleOperatorPrefix,
|
||||
Description: "包含某个前缀",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "包含后缀",
|
||||
Code: HTTPFirewallRuleOperatorSuffix,
|
||||
Description: "包含某个后缀",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "包含索引",
|
||||
Code: HTTPFirewallRuleOperatorHasKey,
|
||||
Description: "对于一组数据拥有某个键值或者索引",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "版本号大于",
|
||||
Code: HTTPFirewallRuleOperatorVersionGt,
|
||||
Description: "对比版本号大于",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "版本号小于",
|
||||
Code: HTTPFirewallRuleOperatorVersionLt,
|
||||
Description: "对比版本号小于",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "版本号范围",
|
||||
Code: HTTPFirewallRuleOperatorVersionRange,
|
||||
Description: "判断版本号在某个范围内,格式为version1,version2",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "IP等于",
|
||||
Code: HTTPFirewallRuleOperatorEqIP,
|
||||
Description: "将参数转换为IP进行对比",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "IP大于",
|
||||
Code: HTTPFirewallRuleOperatorGtIP,
|
||||
Description: "将参数转换为IP进行对比",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "IP大于等于",
|
||||
Code: HTTPFirewallRuleOperatorGteIP,
|
||||
Description: "将参数转换为IP进行对比",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "IP小于",
|
||||
Code: HTTPFirewallRuleOperatorLtIP,
|
||||
Description: "将参数转换为IP进行对比",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "IP小于等于",
|
||||
Code: HTTPFirewallRuleOperatorLteIP,
|
||||
Description: "将参数转换为IP进行对比",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "IP范围",
|
||||
Code: HTTPFirewallRuleOperatorIPRange,
|
||||
Description: "IP在某个范围之内,范围格式可以是英文逗号分隔的ip1,ip2,或者CIDR格式的ip/bits",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "不在IP范围",
|
||||
Code: HTTPFirewallRuleOperatorNotIPRange,
|
||||
Description: "IP不在某个范围之内,范围格式可以是英文逗号分隔的ip1,ip2,或者CIDR格式的ip/bits",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "IP取模10",
|
||||
Code: HTTPFirewallRuleOperatorIPMod10,
|
||||
Description: "对IP参数值取模,除数为10,对比值为余数",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "IP取模100",
|
||||
Code: HTTPFirewallRuleOperatorIPMod100,
|
||||
Description: "对IP参数值取模,除数为100,对比值为余数",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
{
|
||||
Name: "IP取模",
|
||||
Code: HTTPFirewallRuleOperatorIPMod,
|
||||
Description: "对IP参数值取模,对比值格式为:除数,余数,比如10,1",
|
||||
CaseInsensitive: HTTPFirewallRuleCaseInsensitiveNo,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package firewallconfigs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRuleOperator_Markdown(t *testing.T) {
|
||||
result := []string{}
|
||||
for _, def := range AllRuleOperators {
|
||||
row := "## " + def.Name + "\n"
|
||||
row += "符号:`" + def.Code + "`\n"
|
||||
row += "描述:" + def.Description + "\n"
|
||||
result = append(result, row)
|
||||
}
|
||||
|
||||
fmt.Print(strings.Join(result, "\n") + "\n")
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallRuleRef struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
RuleId int64 `yaml:"ruleId" json:"ruleId"`
|
||||
}
|
||||
33
pkg/serverconfigs/firewallconfigs/http_firewall_rule_set.go
Normal file
33
pkg/serverconfigs/firewallconfigs/http_firewall_rule_set.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package firewallconfigs
|
||||
|
||||
import "github.com/iwind/TeaGo/maps"
|
||||
|
||||
// 规则集定义
|
||||
type HTTPFirewallRuleSet struct {
|
||||
Id int64 `yaml:"id" json:"id"`
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Code string `yaml:"code" json:"code"`
|
||||
Description string `yaml:"description" json:"description"`
|
||||
Connector string `yaml:"connector" json:"connector"`
|
||||
RuleRefs []*HTTPFirewallRuleRef `yaml:"ruleRefs" json:"ruleRefs"`
|
||||
Rules []*HTTPFirewallRule `yaml:"rules" json:"rules"`
|
||||
Action string `yaml:"action" json:"action"`
|
||||
ActionOptions maps.Map `yaml:"actionOptions" json:"actionOptions"`
|
||||
}
|
||||
|
||||
// 初始化
|
||||
func (this *HTTPFirewallRuleSet) Init() error {
|
||||
for _, rule := range this.Rules {
|
||||
err := rule.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 添加规则
|
||||
func (this *HTTPFirewallRuleSet) AddRule(rule *HTTPFirewallRule) {
|
||||
this.Rules = append(this.Rules, rule)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallRuleSetRef struct {
|
||||
IsOn bool `yaml:"isOn" json:"isOn"`
|
||||
SetId int64 `yaml:"setId" json:"setId"`
|
||||
}
|
||||
511
pkg/serverconfigs/firewallconfigs/http_firewall_template.go
Normal file
511
pkg/serverconfigs/firewallconfigs/http_firewall_template.go
Normal file
@@ -0,0 +1,511 @@
|
||||
package firewallconfigs
|
||||
|
||||
type HTTPFirewallRuleConnector = string
|
||||
|
||||
const (
|
||||
HTTPFirewallRuleConnectorAnd = "and"
|
||||
HTTPFirewallRuleConnectorOr = "or"
|
||||
)
|
||||
|
||||
func HTTPFirewallTemplate() *HTTPFirewallPolicy {
|
||||
policy := &HTTPFirewallPolicy{}
|
||||
policy.IsOn = true
|
||||
policy.Inbound = &HTTPFirewallInboundConfig{}
|
||||
policy.Outbound = &HTTPFirewallOutboundConfig{}
|
||||
|
||||
// black list
|
||||
{
|
||||
group := &HTTPFirewallRuleGroup{}
|
||||
group.IsOn = false
|
||||
group.Name = "白名单"
|
||||
group.Code = "whiteList"
|
||||
group.Description = "在此名单中的IP地址可以直接跳过防火墙设置"
|
||||
|
||||
{
|
||||
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "IP白名单"
|
||||
set.Code = "9001"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionAllow
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${remoteAddr}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `127\.0\.0\.1|0\.0\.0\.0`,
|
||||
IsCaseInsensitive: false,
|
||||
})
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
policy.Inbound.Groups = append(policy.Inbound.Groups, group)
|
||||
}
|
||||
|
||||
// black list
|
||||
{
|
||||
group := &HTTPFirewallRuleGroup{}
|
||||
group.IsOn = false
|
||||
group.Name = "黑名单"
|
||||
group.Code = "blackList"
|
||||
group.Description = "在此名单中的IP地址直接阻止"
|
||||
|
||||
{
|
||||
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "IP黑名单"
|
||||
set.Code = "10001"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${remoteAddr}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `1\.1\.1\.1|2\.2\.2\.2`,
|
||||
IsCaseInsensitive: false,
|
||||
})
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
policy.Inbound.Groups = append(policy.Inbound.Groups, group)
|
||||
}
|
||||
|
||||
// xss
|
||||
{
|
||||
group := &HTTPFirewallRuleGroup{}
|
||||
group.IsOn = true
|
||||
group.Name = "XSS"
|
||||
group.Code = "xss"
|
||||
group.Description = "防跨站脚本攻击(Cross Site Scripting)"
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "Javascript事件"
|
||||
set.Code = "1001"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestURI}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `(onmouseover|onmousemove|onmousedown|onmouseup|onerror|onload|onclick|ondblclick|onkeydown|onkeyup|onkeypress)\s*=`, // TODO more keywords here
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "Javascript函数"
|
||||
set.Code = "1002"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestURI}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `(alert|eval|prompt|confirm)\s*\(`, // TODO more keywords here
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "HTML标签"
|
||||
set.Code = "1003"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestURI}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `<(script|iframe|link)`, // TODO more keywords here
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
policy.Inbound.Groups = append(policy.Inbound.Groups, group)
|
||||
}
|
||||
|
||||
// upload
|
||||
{
|
||||
group := &HTTPFirewallRuleGroup{}
|
||||
group.IsOn = true
|
||||
group.Name = "文件上传"
|
||||
group.Code = "upload"
|
||||
group.Description = "防止上传可执行脚本文件到服务器"
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "上传文件扩展名"
|
||||
set.Code = "2001"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestUpload.ext}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `\.(php|jsp|aspx|asp|exe|asa|rb|py)\b`, // TODO more keywords here
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
policy.Inbound.Groups = append(policy.Inbound.Groups, group)
|
||||
}
|
||||
|
||||
// web shell
|
||||
{
|
||||
group := &HTTPFirewallRuleGroup{}
|
||||
group.IsOn = true
|
||||
group.Name = "Web Shell"
|
||||
group.Code = "webShell"
|
||||
group.Description = "防止远程执行服务器命令"
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "Web Shell"
|
||||
set.Code = "3001"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestAll}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `\b(eval|system|exec|execute|passthru|shell_exec|phpinfo)\s*\(`, // TODO more keywords here
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
policy.Inbound.Groups = append(policy.Inbound.Groups, group)
|
||||
}
|
||||
|
||||
// command injection
|
||||
{
|
||||
group := &HTTPFirewallRuleGroup{}
|
||||
group.IsOn = true
|
||||
group.Name = "命令注入"
|
||||
group.Code = "commandInjection"
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "命令注入"
|
||||
set.Code = "4001"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestURI}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `\b(pwd|ls|ll|whoami|id|net\s+user)\s*$`, // TODO more keywords here
|
||||
IsCaseInsensitive: false,
|
||||
})
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestBody}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `\b(pwd|ls|ll|whoami|id|net\s+user)\s*$`, // TODO more keywords here
|
||||
IsCaseInsensitive: false,
|
||||
})
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
policy.Inbound.Groups = append(policy.Inbound.Groups, group)
|
||||
}
|
||||
|
||||
// path traversal
|
||||
{
|
||||
group := &HTTPFirewallRuleGroup{}
|
||||
group.IsOn = true
|
||||
group.Name = "路径穿越"
|
||||
group.Code = "pathTraversal"
|
||||
group.Description = "防止读取网站目录之外的其他系统文件"
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "路径穿越"
|
||||
set.Code = "5001"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestURI}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `((\.+)(/+)){2,}`, // TODO more keywords here
|
||||
IsCaseInsensitive: false,
|
||||
})
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
policy.Inbound.Groups = append(policy.Inbound.Groups, group)
|
||||
}
|
||||
|
||||
// special dirs
|
||||
{
|
||||
group := &HTTPFirewallRuleGroup{}
|
||||
group.IsOn = true
|
||||
group.Name = "特殊目录"
|
||||
group.Code = "denyDirs"
|
||||
group.Description = "防止通过Web访问到一些特殊目录"
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "特殊目录"
|
||||
set.Code = "6001"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestPath}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `/\.(git|svn|htaccess|idea)\b`, // TODO more keywords here
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
policy.Inbound.Groups = append(policy.Inbound.Groups, group)
|
||||
}
|
||||
|
||||
// sql injection
|
||||
{
|
||||
group := &HTTPFirewallRuleGroup{}
|
||||
group.IsOn = true
|
||||
group.Name = "SQL注入"
|
||||
group.Code = "sqlInjection"
|
||||
group.Description = "防止SQL注入漏洞"
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "Union SQL Injection"
|
||||
set.Code = "7001"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestAll}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `union[\s/\*]+select`,
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "SQL注释"
|
||||
set.Code = "7002"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestAll}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `/\*(!|\x00)`,
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "SQL条件"
|
||||
set.Code = "7003"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestAll}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `\s(and|or|rlike)\s+(if|updatexml)\s*\(`,
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestAll}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `\s+(and|or|rlike)\s+(select|case)\s+`,
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestAll}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `\s+(and|or|procedure)\s+[\w\p{L}]+\s*=\s*[\w\p{L}]+(\s|$|--|#)`,
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestAll}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `\(\s*case\s+when\s+[\w\p{L}]+\s*=\s*[\w\p{L}]+\s+then\s+`,
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "SQL函数"
|
||||
set.Code = "7004"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestAll}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `(updatexml|extractvalue|ascii|ord|char|chr|count|concat|rand|floor|substr|length|len|user|database|benchmark|analyse)\s*\(`,
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "SQL附加语句"
|
||||
set.Code = "7005"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${requestAll}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `;\s*(declare|use|drop|create|exec|delete|update|insert)\s`,
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
policy.Inbound.Groups = append(policy.Inbound.Groups, group)
|
||||
}
|
||||
|
||||
// bot
|
||||
{
|
||||
group := &HTTPFirewallRuleGroup{}
|
||||
group.IsOn = true
|
||||
group.Name = "网络爬虫"
|
||||
group.Code = "bot"
|
||||
group.Description = "禁止一些网络爬虫"
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "常见网络爬虫"
|
||||
set.Code = "20001"
|
||||
set.Connector = HTTPFirewallRuleConnectorOr
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${userAgent}",
|
||||
Operator: HTTPFirewallRuleOperatorMatch,
|
||||
Value: `Googlebot|AdsBot|bingbot|BingPreview|facebookexternalhit|Slurp|Sogou|proximic|Baiduspider|yandex|twitterbot|spider|python`,
|
||||
IsCaseInsensitive: true,
|
||||
})
|
||||
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
policy.Inbound.Groups = append(policy.Inbound.Groups, group)
|
||||
}
|
||||
|
||||
// cc
|
||||
{
|
||||
group := &HTTPFirewallRuleGroup{}
|
||||
group.IsOn = true
|
||||
group.Name = "CC攻击"
|
||||
group.Description = "Challenge Collapsar,防止短时间大量请求涌入,请谨慎开启和设置"
|
||||
group.Code = "cc"
|
||||
|
||||
{
|
||||
set := &HTTPFirewallRuleSet{}
|
||||
set.IsOn = true
|
||||
set.Name = "CC请求数"
|
||||
set.Description = "限制单IP在一定时间内的请求数"
|
||||
set.Code = "8001"
|
||||
set.Connector = HTTPFirewallRuleConnectorAnd
|
||||
set.Action = HTTPFirewallActionBlock
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${cc.requests}",
|
||||
Operator: HTTPFirewallRuleOperatorGt,
|
||||
Value: "1000",
|
||||
CheckpointOptions: map[string]interface{}{
|
||||
"period": "60",
|
||||
},
|
||||
IsCaseInsensitive: false,
|
||||
})
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${remoteAddr}",
|
||||
Operator: HTTPFirewallRuleOperatorNotIPRange,
|
||||
Value: `127.0.0.1/8`,
|
||||
IsCaseInsensitive: false,
|
||||
})
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${remoteAddr}",
|
||||
Operator: HTTPFirewallRuleOperatorNotIPRange,
|
||||
Value: `192.168.0.1/16`,
|
||||
IsCaseInsensitive: false,
|
||||
})
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${remoteAddr}",
|
||||
Operator: HTTPFirewallRuleOperatorNotIPRange,
|
||||
Value: `10.0.0.1/8`,
|
||||
IsCaseInsensitive: false,
|
||||
})
|
||||
set.AddRule(&HTTPFirewallRule{
|
||||
IsOn: true,
|
||||
Param: "${remoteAddr}",
|
||||
Operator: HTTPFirewallRuleOperatorNotIPRange,
|
||||
Value: `172.16.0.1/12`,
|
||||
IsCaseInsensitive: false,
|
||||
})
|
||||
|
||||
group.AddRuleSet(set)
|
||||
}
|
||||
|
||||
policy.Inbound.Groups = append(policy.Inbound.Groups, group)
|
||||
}
|
||||
|
||||
// custom
|
||||
{
|
||||
group := &HTTPFirewallRuleGroup{}
|
||||
group.IsOn = true
|
||||
group.Name = "自定义规则分组"
|
||||
group.Description = "我的自定义规则分组,可以将自定义的规则放在这个分组下"
|
||||
group.Code = "custom"
|
||||
policy.Inbound.Groups = append(policy.Inbound.Groups, group)
|
||||
}
|
||||
|
||||
return policy
|
||||
}
|
||||
@@ -1,28 +1,32 @@
|
||||
package serverconfigs
|
||||
|
||||
import "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||||
)
|
||||
|
||||
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 *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策略
|
||||
@@ -125,6 +129,12 @@ 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 {
|
||||
|
||||
147
pkg/serverconfigs/shared/ip_range.go
Normal file
147
pkg/serverconfigs/shared/ip_range.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"github.com/iwind/TeaGo/utils/string"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IP Range类型
|
||||
type IPRangeType = int
|
||||
|
||||
const (
|
||||
IPRangeTypeRange IPRangeType = 1
|
||||
IPRangeTypeCIDR IPRangeType = 2
|
||||
IPRangeTypeAll IPRangeType = 3
|
||||
IPRangeTypeWildcard IPRangeType = 4 // 通配符,可以使用*
|
||||
)
|
||||
|
||||
// IP Range
|
||||
type IPRangeConfig struct {
|
||||
Id string `yaml:"id" json:"id"`
|
||||
|
||||
Type IPRangeType `yaml:"type" json:"type"`
|
||||
|
||||
Param string `yaml:"param" json:"param"`
|
||||
CIDR string `yaml:"cidr" json:"cidr"`
|
||||
IPFrom string `yaml:"ipFrom" json:"ipFrom"`
|
||||
IPTo string `yaml:"ipTo" json:"ipTo"`
|
||||
|
||||
cidr *net.IPNet
|
||||
ipFrom net.IP
|
||||
ipTo net.IP
|
||||
reg *regexp.Regexp
|
||||
}
|
||||
|
||||
// 获取新对象
|
||||
func NewIPRangeConfig() *IPRangeConfig {
|
||||
return &IPRangeConfig{
|
||||
Id: stringutil.Rand(16),
|
||||
}
|
||||
}
|
||||
|
||||
// 从字符串中分析
|
||||
func ParseIPRange(s string) (*IPRangeConfig, error) {
|
||||
if len(s) == 0 {
|
||||
return nil, errors.New("invalid ip range")
|
||||
}
|
||||
|
||||
ipRange := &IPRangeConfig{}
|
||||
|
||||
if s == "*" || s == "all" || s == "ALL" || s == "0.0.0.0" {
|
||||
ipRange.Type = IPRangeTypeAll
|
||||
return ipRange, nil
|
||||
}
|
||||
|
||||
if strings.Contains(s, "/") {
|
||||
ipRange.Type = IPRangeTypeCIDR
|
||||
ipRange.CIDR = strings.Replace(s, " ", "", -1)
|
||||
} else if strings.Contains(s, "-") {
|
||||
ipRange.Type = IPRangeTypeRange
|
||||
pieces := strings.SplitN(s, "-", 2)
|
||||
ipRange.IPFrom = strings.TrimSpace(pieces[0])
|
||||
ipRange.IPTo = strings.TrimSpace(pieces[1])
|
||||
} else if strings.Contains(s, ",") {
|
||||
ipRange.Type = IPRangeTypeRange
|
||||
pieces := strings.SplitN(s, ",", 2)
|
||||
ipRange.IPFrom = strings.TrimSpace(pieces[0])
|
||||
ipRange.IPTo = strings.TrimSpace(pieces[1])
|
||||
} else if strings.Contains(s, "*") {
|
||||
ipRange.Type = IPRangeTypeWildcard
|
||||
s = "^" + strings.Replace(regexp.QuoteMeta(s), `\*`, `\d+`, -1) + "$"
|
||||
ipRange.reg = regexp.MustCompile(s)
|
||||
} else {
|
||||
ipRange.Type = IPRangeTypeRange
|
||||
ipRange.IPFrom = s
|
||||
ipRange.IPTo = s
|
||||
}
|
||||
|
||||
err := ipRange.Validate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ipRange, nil
|
||||
}
|
||||
|
||||
// 校验
|
||||
func (this *IPRangeConfig) Validate() error {
|
||||
if this.Type == IPRangeTypeCIDR {
|
||||
if len(this.CIDR) == 0 {
|
||||
return errors.New("cidr should not be empty")
|
||||
}
|
||||
|
||||
_, cidr, err := net.ParseCIDR(this.CIDR)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
this.cidr = cidr
|
||||
}
|
||||
|
||||
if this.Type == IPRangeTypeRange {
|
||||
this.ipFrom = net.ParseIP(this.IPFrom)
|
||||
this.ipTo = net.ParseIP(this.IPTo)
|
||||
|
||||
if this.ipFrom.To4() == nil && this.ipFrom.To16() == nil {
|
||||
return errors.New("from ip should in IPv4 or IPV6 format")
|
||||
}
|
||||
|
||||
if this.ipTo.To4() == nil && this.ipTo.To16() == nil {
|
||||
return errors.New("to ip should in IPv4 or IPV6 format")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 是否包含某个IP
|
||||
func (this *IPRangeConfig) Contains(ipString string) bool {
|
||||
ip := net.ParseIP(ipString)
|
||||
if ip.To4() == nil {
|
||||
return false
|
||||
}
|
||||
if this.Type == IPRangeTypeCIDR {
|
||||
if this.cidr == nil {
|
||||
return false
|
||||
}
|
||||
return this.cidr.Contains(ip)
|
||||
}
|
||||
if this.Type == IPRangeTypeRange {
|
||||
if this.ipFrom == nil || this.ipTo == nil {
|
||||
return false
|
||||
}
|
||||
return bytes.Compare(ip, this.ipFrom) >= 0 && bytes.Compare(ip, this.ipTo) <= 0
|
||||
}
|
||||
if this.Type == IPRangeTypeWildcard {
|
||||
if this.reg == nil {
|
||||
return false
|
||||
}
|
||||
return this.reg.MatchString(ipString)
|
||||
}
|
||||
if this.Type == IPRangeTypeAll {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
125
pkg/serverconfigs/shared/ip_range_test.go
Normal file
125
pkg/serverconfigs/shared/ip_range_test.go
Normal file
@@ -0,0 +1,125 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"github.com/iwind/TeaGo/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGeoConfig_Contains(t *testing.T) {
|
||||
a := assert.NewAssertion(t)
|
||||
|
||||
{
|
||||
geo := NewIPRangeConfig()
|
||||
geo.Type = IPRangeTypeRange
|
||||
geo.IPFrom = "192.168.1.100"
|
||||
geo.IPTo = "192.168.1.110"
|
||||
a.IsNil(geo.Validate())
|
||||
a.IsTrue(geo.Contains("192.168.1.100"))
|
||||
a.IsTrue(geo.Contains("192.168.1.101"))
|
||||
a.IsTrue(geo.Contains("192.168.1.110"))
|
||||
a.IsFalse(geo.Contains("192.168.1.111"))
|
||||
}
|
||||
|
||||
{
|
||||
geo := NewIPRangeConfig()
|
||||
geo.Type = IPRangeTypeCIDR
|
||||
geo.CIDR = "192.168.1.1/24"
|
||||
a.IsNil(geo.Validate())
|
||||
a.IsTrue(geo.Contains("192.168.1.100"))
|
||||
a.IsFalse(geo.Contains("192.168.2.100"))
|
||||
}
|
||||
|
||||
{
|
||||
geo := NewIPRangeConfig()
|
||||
geo.Type = IPRangeTypeCIDR
|
||||
geo.CIDR = "192.168.1.1/16"
|
||||
a.IsNil(geo.Validate())
|
||||
a.IsTrue(geo.Contains("192.168.2.100"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseIPRange(t *testing.T) {
|
||||
a := assert.NewAssertion(t)
|
||||
|
||||
{
|
||||
_, err := ParseIPRange("")
|
||||
a.IsNotNil(err)
|
||||
}
|
||||
|
||||
{
|
||||
r, err := ParseIPRange("192.168.1.100")
|
||||
a.IsNil(err)
|
||||
a.IsTrue(r.IPFrom == r.IPTo)
|
||||
a.IsTrue(r.IPFrom == "192.168.1.100")
|
||||
a.IsTrue(r.Contains("192.168.1.100"))
|
||||
a.IsFalse(r.Contains("192.168.1.99"))
|
||||
}
|
||||
|
||||
{
|
||||
r, err := ParseIPRange("192.168.1.100/24")
|
||||
a.IsNil(err)
|
||||
a.IsTrue(r.CIDR == "192.168.1.100/24")
|
||||
a.IsTrue(r.Contains("192.168.1.100"))
|
||||
a.IsTrue(r.Contains("192.168.1.99"))
|
||||
a.IsFalse(r.Contains("192.168.2.100"))
|
||||
}
|
||||
|
||||
{
|
||||
r, err := ParseIPRange("192.168.1.100, 192.168.1.200")
|
||||
a.IsNil(err)
|
||||
a.IsTrue(r.IPFrom == "192.168.1.100")
|
||||
a.IsTrue(r.IPTo == "192.168.1.200")
|
||||
a.IsTrue(r.Contains("192.168.1.100"))
|
||||
a.IsTrue(r.Contains("192.168.1.150"))
|
||||
a.IsFalse(r.Contains("192.168.2.100"))
|
||||
}
|
||||
|
||||
{
|
||||
r, err := ParseIPRange("192.168.1.100-192.168.1.200")
|
||||
a.IsNil(err)
|
||||
a.IsTrue(r.IPFrom == "192.168.1.100")
|
||||
a.IsTrue(r.IPTo == "192.168.1.200")
|
||||
a.IsTrue(r.Contains("192.168.1.100"))
|
||||
a.IsTrue(r.Contains("192.168.1.150"))
|
||||
a.IsFalse(r.Contains("192.168.2.100"))
|
||||
}
|
||||
|
||||
{
|
||||
r, err := ParseIPRange("all")
|
||||
a.IsNil(err)
|
||||
a.IsTrue(r.Type == IPRangeTypeAll)
|
||||
a.IsTrue(r.Contains("192.168.1.100"))
|
||||
a.IsTrue(r.Contains("192.168.1.150"))
|
||||
a.IsTrue(r.Contains("192.168.2.100"))
|
||||
}
|
||||
|
||||
{
|
||||
r, err := ParseIPRange("192.168.1.*")
|
||||
a.IsNil(err)
|
||||
if r != nil {
|
||||
a.IsTrue(r.Type == IPRangeTypeWildcard)
|
||||
a.IsTrue(r.Contains("192.168.1.100"))
|
||||
a.IsFalse(r.Contains("192.168.2.100"))
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
r, err := ParseIPRange("192.168.*.*")
|
||||
a.IsNil(err)
|
||||
if r != nil {
|
||||
a.IsTrue(r.Type == IPRangeTypeWildcard)
|
||||
a.IsTrue(r.Contains("192.168.1.100"))
|
||||
a.IsTrue(r.Contains("192.168.2.100"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIPRangeConfig_Contains(b *testing.B) {
|
||||
r, err := ParseIPRange("192.168.1.*")
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = r.Contains("192.168.1.100")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user