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  }