diff --git a/config_example/rules/HTTPFlood.yml b/config_example/rules/HTTPFlood.yml new file mode 100644 index 0000000..ed4f43b --- /dev/null +++ b/config_example/rules/HTTPFlood.yml @@ -0,0 +1,4 @@ +HTTPFloodSpeedLimit: + - "150/10s" +HTTPFloodSameURILimit: + - "50/10s" \ No newline at end of file diff --git a/internal/config/config.go b/internal/config/config.go index 0ddf1fe..d00fb48 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -8,6 +8,7 @@ import ( "path/filepath" "regexp" "server_torii/internal/dataType" + "server_torii/internal/utils" "strings" ) @@ -56,6 +57,7 @@ type RuleSet struct { URLBlockList *dataType.URLRuleList CAPTCHARule *dataType.CaptchaRule VerifyBotRule *dataType.VerifyBotRule + HTTPFloodRule *dataType.HTTPFloodRule } // LoadRules Load all rules from the specified path @@ -67,6 +69,7 @@ func LoadRules(rulePath string) (*RuleSet, error) { URLBlockList: &dataType.URLRuleList{}, CAPTCHARule: &dataType.CaptchaRule{}, VerifyBotRule: &dataType.VerifyBotRule{}, + HTTPFloodRule: &dataType.HTTPFloodRule{}, } // Load IP Allow List @@ -105,6 +108,12 @@ func LoadRules(rulePath string) (*RuleSet, error) { return nil, err } + // Load HTTP Flood Rule + httpFloodFile := rulePath + "/HTTPFlood.yml" + if err := loadHTTPFloodRule(httpFloodFile, rs.HTTPFloodRule); err != nil { + return nil, err + } + return &rs, nil } @@ -208,3 +217,43 @@ func loadURLRules(filePath string, list *dataType.URLRuleList) error { return scanner.Err() } + +func loadHTTPFloodRule(file string, rule *dataType.HTTPFloodRule) error { + data, err := os.ReadFile(file) + if err != nil { + return err + } + + type httpFloodRuleYAML struct { + HTTPFloodSpeedLimit []string `yaml:"HTTPFloodSpeedLimit"` + HTTPFloodSameURILimit []string `yaml:"HTTPFloodSameURILimit"` + } + + var ymlRule httpFloodRuleYAML + err = yaml.Unmarshal(data, &ymlRule) + if err != nil { + return err + } + + rule.HTTPFloodSpeedLimit = make(map[int]int) + rule.HTTPFloodSameURILimit = make(map[int]int) + + for _, s := range ymlRule.HTTPFloodSpeedLimit { + limit, seconds, err := utils.ParseRate(s) + if err != nil { + return err + } + rule.HTTPFloodSpeedLimit[seconds] = limit + } + + for _, s := range ymlRule.HTTPFloodSameURILimit { + limit, seconds, err := utils.ParseRate(s) + if err != nil { + return err + } + rule.HTTPFloodSameURILimit[seconds] = limit + } + + return nil + +} diff --git a/internal/dataType/type.go b/internal/dataType/type.go index 4f247b9..f522f20 100644 --- a/internal/dataType/type.go +++ b/internal/dataType/type.go @@ -25,3 +25,11 @@ type VerifyBotRule struct { VerifySogouBot bool `yaml:"verify_sogou_bot"` VerifyAppleBot bool `yaml:"verify_apple_bot"` } + +type HTTPFloodRule struct { + HTTPFloodSpeedLimit map[int]int + HTTPFloodSameURILimit map[int]int +} + +type SharedMemory struct { +} diff --git a/internal/utils/RateParser.go b/internal/utils/RateParser.go new file mode 100644 index 0000000..8f4fb36 --- /dev/null +++ b/internal/utils/RateParser.go @@ -0,0 +1,41 @@ +package utils + +import ( + "fmt" + "strconv" + "strings" +) + +func ParseRate(s string) (int, int, error) { + parts := strings.Split(s, "/") + if len(parts) != 2 { + return 0, 0, fmt.Errorf("unexpected rate format: %s", s) + } + limit, err := strconv.Atoi(parts[0]) + if err != nil { + return 0, 0, fmt.Errorf("unexpected rate format: %s", s) + } + + timeStr := parts[1] + if len(timeStr) < 2 { + return 0, 0, fmt.Errorf("unexpected time format: %s", timeStr) + } + unit := timeStr[len(timeStr)-1] + numPart := timeStr[:len(timeStr)-1] + value, err := strconv.Atoi(numPart) + if err != nil { + return 0, 0, fmt.Errorf("unexpected time format: %s", timeStr) + } + var seconds int + switch unit { + case 's': + seconds = value + case 'm': + seconds = value * 60 + case 'h': + seconds = value * 3600 + default: + return 0, 0, fmt.Errorf("unexpected time unit: %s", string(unit)) + } + return limit, seconds, nil +} diff --git a/main.go b/main.go index f0d7fbd..6d619b2 100644 --- a/main.go +++ b/main.go @@ -46,6 +46,8 @@ func main() { }(logFile) log.SetOutput(logFile) + //allocate shared memory + // Start server stop := make(chan os.Signal, 1) signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)