177 lines
5.6 KiB
Go
177 lines
5.6 KiB
Go
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||
//go:build plus
|
||
|
||
package serverconfigs
|
||
|
||
import (
|
||
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
||
)
|
||
|
||
type HTTPCCLevel = string
|
||
|
||
// DefaultHTTPCCConfig 默认的CC配置
|
||
func DefaultHTTPCCConfig() *HTTPCCConfig {
|
||
return &HTTPCCConfig{
|
||
EnableFingerprint: true,
|
||
EnableGET302: true,
|
||
UseDefaultThresholds: true,
|
||
IgnoreCommonFiles: true,
|
||
}
|
||
}
|
||
|
||
const (
|
||
HTTPCCLevelLow HTTPCCLevel = "low"
|
||
HTTPCCLevelMiddle HTTPCCLevel = "middle"
|
||
HTTPCCLevelHigh HTTPCCLevel = "high"
|
||
)
|
||
|
||
type HTTPCCThreshold struct {
|
||
PeriodSeconds int32 `yaml:"periodSeconds" json:"periodSeconds"` // 计算周期
|
||
MaxRequests int32 `yaml:"maxRequests" json:"maxRequests"` // 请求数最大值
|
||
//MaxConnections int32 `yaml:"maxConnections" json:"maxConnections"` // 连接数最大值 TODO
|
||
BlockSeconds int32 `yaml:"blockSeconds" json:"blockSeconds"` // 拦截时间
|
||
}
|
||
|
||
func NewHTTPCCThreshold() *HTTPCCThreshold {
|
||
return &HTTPCCThreshold{}
|
||
}
|
||
|
||
func (this *HTTPCCThreshold) Merge(threshold *HTTPCCThreshold) {
|
||
if threshold.PeriodSeconds > 0 {
|
||
this.PeriodSeconds = threshold.PeriodSeconds
|
||
}
|
||
if threshold.MaxRequests > 0 {
|
||
this.MaxRequests = threshold.MaxRequests
|
||
}
|
||
if threshold.BlockSeconds > 0 {
|
||
this.BlockSeconds = threshold.BlockSeconds
|
||
}
|
||
}
|
||
|
||
func (this *HTTPCCThreshold) MergeIfEmpty(threshold *HTTPCCThreshold) {
|
||
if threshold.PeriodSeconds > 0 && this.PeriodSeconds <= 0 {
|
||
this.PeriodSeconds = threshold.PeriodSeconds
|
||
}
|
||
if threshold.MaxRequests > 0 && this.MaxRequests <= 0 {
|
||
this.MaxRequests = threshold.MaxRequests
|
||
}
|
||
if threshold.BlockSeconds > 0 && this.BlockSeconds <= 0 {
|
||
this.BlockSeconds = threshold.BlockSeconds
|
||
}
|
||
}
|
||
|
||
func (this *HTTPCCThreshold) Clone() *HTTPCCThreshold {
|
||
return &HTTPCCThreshold{
|
||
PeriodSeconds: this.PeriodSeconds,
|
||
MaxRequests: this.MaxRequests,
|
||
BlockSeconds: this.BlockSeconds,
|
||
}
|
||
}
|
||
|
||
const (
|
||
DefaultHTTPCCThresholdPeriodSeconds0 = 5
|
||
DefaultHTTPCCThresholdPeriodSeconds1 = 60
|
||
DefaultHTTPCCThresholdPeriodSeconds2 = 300
|
||
|
||
DefaultHTTPCCThresholdBlockSeconds0 = 600
|
||
DefaultHTTPCCThresholdBlockSeconds1 = 2400
|
||
DefaultHTTPCCThresholdBlockSeconds2 = 3600
|
||
)
|
||
|
||
var DefaultHTTPCCThresholds = []*HTTPCCThreshold{
|
||
{
|
||
PeriodSeconds: DefaultHTTPCCThresholdPeriodSeconds0,
|
||
MaxRequests: 60,
|
||
BlockSeconds: DefaultHTTPCCThresholdBlockSeconds0,
|
||
},
|
||
{
|
||
PeriodSeconds: DefaultHTTPCCThresholdPeriodSeconds1,
|
||
MaxRequests: 150,
|
||
BlockSeconds: DefaultHTTPCCThresholdBlockSeconds1,
|
||
},
|
||
{
|
||
PeriodSeconds: DefaultHTTPCCThresholdPeriodSeconds2,
|
||
MaxRequests: 300,
|
||
BlockSeconds: DefaultHTTPCCThresholdBlockSeconds2,
|
||
},
|
||
}
|
||
|
||
func CloneDefaultHTTPCCThresholds() []*HTTPCCThreshold {
|
||
var result = []*HTTPCCThreshold{}
|
||
for _, threshold := range DefaultHTTPCCThresholds {
|
||
result = append(result, threshold.Clone())
|
||
}
|
||
return result
|
||
}
|
||
|
||
// HTTPCCConfig HTTP CC防护配置
|
||
type HTTPCCConfig struct {
|
||
IsPrior bool `yaml:"isPrior" json:"isPrior"` // 是否覆盖父级
|
||
IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用
|
||
Level HTTPCCLevel `yaml:"level" json:"level"` // 级别 TODO
|
||
WithRequestPath bool `yaml:"withRequestPath" json:"withRequestPath"` // 根据URL路径区分请求 TODO
|
||
UseDefaultThresholds bool `yaml:"useDefaultThresholds" json:"useDefaultThresholds"` // 是否使用默认的阈值设置
|
||
Thresholds []*HTTPCCThreshold `yaml:"thresholds" json:"thresholds"` // 阈值设置
|
||
IgnoreCommonFiles bool `yaml:"ignoreCommonFiles" json:"ignoreCommonFiles"` // 忽略常用文件,如CSS、JS等
|
||
IgnoreCommonAgents bool `yaml:"ignoreCommonAgents" json:"ignoreCommonAgents"` // 忽略常见搜索引擎等 TODO
|
||
Action string `yaml:"action" json:"action"` // 动作,比如block、captcha等 TODO
|
||
OnlyURLPatterns []*shared.URLPattern `yaml:"onlyURLPatterns" json:"onlyURLPatterns"` // 仅限的URL
|
||
ExceptURLPatterns []*shared.URLPattern `yaml:"exceptURLPatterns" json:"exceptURLPatterns"` // 排除的URL
|
||
EnableFingerprint bool `yaml:"enableFingerprint" json:"enableFingerprint"` // 是否检查请求来源指纹
|
||
EnableGET302 bool `yaml:"enableGET302" json:"enableGET302"` // 是否支持GET302校验
|
||
MinQPSPerIP int `yaml:"minQPSPerIP" json:"minQPSPerIP"` // 启用要求的单IP最低平均QPS
|
||
}
|
||
|
||
func NewHTTPCCConfig() *HTTPCCConfig {
|
||
return &HTTPCCConfig{
|
||
WithRequestPath: false,
|
||
IgnoreCommonFiles: true,
|
||
IgnoreCommonAgents: true,
|
||
Action: "captcha",
|
||
EnableFingerprint: true,
|
||
EnableGET302: true,
|
||
}
|
||
}
|
||
|
||
func (this *HTTPCCConfig) Init() error {
|
||
// only urls
|
||
for _, pattern := range this.OnlyURLPatterns {
|
||
err := pattern.Init()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
// except urls
|
||
for _, pattern := range this.ExceptURLPatterns {
|
||
err := pattern.Init()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func (this *HTTPCCConfig) MatchURL(url string) bool {
|
||
// except
|
||
if len(this.ExceptURLPatterns) > 0 {
|
||
for _, pattern := range this.ExceptURLPatterns {
|
||
if pattern.Match(url) {
|
||
return false
|
||
}
|
||
}
|
||
}
|
||
|
||
if len(this.OnlyURLPatterns) > 0 {
|
||
for _, pattern := range this.OnlyURLPatterns {
|
||
if pattern.Match(url) {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
return true
|
||
}
|