github.com/TeaOSLab/EdgeNode@v1.3.8/internal/waf/checkpoints/cc.go (about) 1 package checkpoints 2 3 import ( 4 "github.com/TeaOSLab/EdgeNode/internal/utils/counters" 5 "github.com/TeaOSLab/EdgeNode/internal/waf/requests" 6 "github.com/TeaOSLab/EdgeNode/internal/waf/utils" 7 "github.com/iwind/TeaGo/maps" 8 "github.com/iwind/TeaGo/types" 9 "regexp" 10 ) 11 12 // CCCheckpoint ${cc.arg} 13 // TODO implement more traffic rules 14 type CCCheckpoint struct { 15 Checkpoint 16 } 17 18 func (this *CCCheckpoint) Init() { 19 20 } 21 22 func (this *CCCheckpoint) Start() { 23 24 } 25 26 func (this *CCCheckpoint) RequestValue(req requests.Request, param string, options maps.Map, ruleId int64) (value any, hasRequestBody bool, sysErr error, userErr error) { 27 value = 0 28 29 periodString, ok := options["period"] 30 if !ok { 31 return 32 } 33 var period = types.Int(periodString) 34 if period < 1 { 35 return 36 } 37 38 if period > 7*86400 { 39 period = 7 * 86400 40 } 41 42 var userType = types.String(options["userType"]) 43 var userField = types.String(options["userField"]) 44 var userIndex = types.Int(options["userIndex"]) 45 46 if param == "requests" { // requests 47 var key = "" 48 switch userType { 49 case "ip": 50 key = req.WAFRemoteIP() 51 case "cookie": 52 if len(userField) == 0 { 53 key = req.WAFRemoteIP() 54 } else { 55 cookie, _ := req.WAFRaw().Cookie(userField) 56 if cookie != nil { 57 v := cookie.Value 58 if userIndex > 0 && len(v) > userIndex { 59 v = v[userIndex:] 60 } 61 key = "USER@" + userType + "@" + userField + "@" + v 62 } 63 } 64 case "get": 65 if len(userField) == 0 { 66 key = req.WAFRemoteIP() 67 } else { 68 v := req.WAFRaw().URL.Query().Get(userField) 69 if userIndex > 0 && len(v) > userIndex { 70 v = v[userIndex:] 71 } 72 key = "USER@" + userType + "@" + userField + "@" + v 73 } 74 case "post": 75 if len(userField) == 0 { 76 key = req.WAFRemoteIP() 77 } else { 78 v := req.WAFRaw().PostFormValue(userField) 79 if userIndex > 0 && len(v) > userIndex { 80 v = v[userIndex:] 81 } 82 key = "USER@" + userType + "@" + userField + "@" + v 83 } 84 case "header": 85 if len(userField) == 0 { 86 key = req.WAFRemoteIP() 87 } else { 88 v := req.WAFRaw().Header.Get(userField) 89 if userIndex > 0 && len(v) > userIndex { 90 v = v[userIndex:] 91 } 92 key = "USER@" + userType + "@" + userField + "@" + v 93 } 94 default: 95 key = req.WAFRemoteIP() 96 } 97 if len(key) == 0 { 98 key = req.WAFRemoteIP() 99 } 100 value = counters.SharedCounter.IncreaseKey(types.String(ruleId)+"@WAF_CC@"+key, types.Int(period)) 101 } 102 103 return 104 } 105 106 func (this *CCCheckpoint) ResponseValue(req requests.Request, resp *requests.Response, param string, options maps.Map, ruleId int64) (value any, hasRequestBody bool, sysErr error, userErr error) { 107 if this.IsRequest() { 108 return this.RequestValue(req, param, options, ruleId) 109 } 110 return 111 } 112 113 func (this *CCCheckpoint) ParamOptions() *ParamOptions { 114 option := NewParamOptions() 115 option.AddParam("请求数", "requests") 116 return option 117 } 118 119 func (this *CCCheckpoint) Options() []OptionInterface { 120 options := []OptionInterface{} 121 122 // period 123 { 124 option := NewFieldOption("统计周期", "period") 125 option.Value = "60" 126 option.RightLabel = "秒" 127 option.Size = 8 128 option.MaxLength = 8 129 option.Validate = func(value string) (ok bool, message string) { 130 if regexp.MustCompile(`^\d+$`).MatchString(value) { 131 ok = true 132 return 133 } 134 message = "周期需要是一个整数数字" 135 return 136 } 137 options = append(options, option) 138 } 139 140 // type 141 { 142 option := NewOptionsOption("用户识别读取来源", "userType") 143 option.Size = 10 144 option.SetOptions([]maps.Map{ 145 { 146 "name": "IP", 147 "value": "ip", 148 }, 149 { 150 "name": "Cookie", 151 "value": "cookie", 152 }, 153 { 154 "name": "URL参数", 155 "value": "get", 156 }, 157 { 158 "name": "POST参数", 159 "value": "post", 160 }, 161 { 162 "name": "HTTP Header", 163 "value": "header", 164 }, 165 }) 166 options = append(options, option) 167 } 168 169 // user field 170 { 171 option := NewFieldOption("用户识别字段", "userField") 172 option.Comment = "识别用户的唯一性字段,在用户读取来源不是IP时使用" 173 options = append(options, option) 174 } 175 176 // user value index 177 { 178 option := NewFieldOption("字段读取位置", "userIndex") 179 option.Size = 5 180 option.MaxLength = 5 181 option.Comment = "读取用户识别字段的位置,从0开始,比如user12345的数字ID 12345的位置就是5,在用户读取来源不是IP时使用" 182 options = append(options, option) 183 } 184 185 return options 186 } 187 188 func (this *CCCheckpoint) Stop() { 189 190 } 191 192 func (this *CCCheckpoint) CacheLife() utils.CacheLife { 193 return utils.CacheDisabled 194 }