reset_filter.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. package leakybucket
  2. import (
  3. "github.com/antonmedv/expr"
  4. "github.com/antonmedv/expr/vm"
  5. "github.com/crowdsecurity/crowdsec/pkg/exprhelpers"
  6. "github.com/crowdsecurity/crowdsec/pkg/types"
  7. )
  8. // ResetFilter allows to kill the bucket (without overflowing), if a particular condition is met.
  9. // An example would be a scenario to detect aggressive crawlers that *do not* fetch any static resources :
  10. // type : leaky
  11. // filter: filter: "evt.Meta.log_type == 'http_access-log'
  12. // reset_filter: evt.Parsed.request endswith '.css'
  13. // ....
  14. // Thus, if the bucket receives a request that matches fetching a static resource (here css), it cancels itself
  15. type CancelOnFilter struct {
  16. CancelOnFilter *vm.Program
  17. CancelOnFilterDebug *exprhelpers.ExprDebugger
  18. }
  19. func (u *CancelOnFilter) OnBucketPour(bucketFactory *BucketFactory) func(types.Event, *Leaky) *types.Event {
  20. return func(msg types.Event, leaky *Leaky) *types.Event {
  21. var condition, ok bool
  22. if u.CancelOnFilter != nil {
  23. leaky.logger.Tracef("running cancel_on filter")
  24. output, err := expr.Run(u.CancelOnFilter, exprhelpers.GetExprEnv(map[string]interface{}{"evt": &msg}))
  25. if err != nil {
  26. leaky.logger.Warningf("cancel_on error : %s", err)
  27. return &msg
  28. }
  29. //only run debugger expression if condition is false
  30. if u.CancelOnFilterDebug != nil {
  31. u.CancelOnFilterDebug.Run(leaky.logger, condition, exprhelpers.GetExprEnv(map[string]interface{}{"evt": &msg}))
  32. }
  33. if condition, ok = output.(bool); !ok {
  34. leaky.logger.Warningf("cancel_on, unexpected non-bool return : %T", output)
  35. return &msg
  36. }
  37. if condition {
  38. leaky.logger.Debugf("reset_filter matched, kill bucket")
  39. leaky.Suicide <- true
  40. return nil //counter intuitively, we need to keep the message so that it doesn't trigger an endless loop
  41. }
  42. leaky.logger.Debugf("reset_filter didn't match")
  43. }
  44. return &msg
  45. }
  46. }
  47. func (u *CancelOnFilter) OnBucketOverflow(bucketFactory *BucketFactory) func(*Leaky, types.RuntimeAlert, *Queue) (types.RuntimeAlert, *Queue) {
  48. return func(leaky *Leaky, alert types.RuntimeAlert, queue *Queue) (types.RuntimeAlert, *Queue) {
  49. return alert, queue
  50. }
  51. }
  52. func (u *CancelOnFilter) OnBucketInit(bucketFactory *BucketFactory) error {
  53. var err error
  54. u.CancelOnFilter, err = expr.Compile(bucketFactory.CancelOnFilter, expr.Env(exprhelpers.GetExprEnv(map[string]interface{}{"evt": &types.Event{}})))
  55. if err != nil {
  56. bucketFactory.logger.Errorf("reset_filter compile error : %s", err)
  57. return err
  58. }
  59. if bucketFactory.Debug {
  60. u.CancelOnFilterDebug, err = exprhelpers.NewDebugger(bucketFactory.CancelOnFilter, expr.Env(exprhelpers.GetExprEnv(map[string]interface{}{"evt": &types.Event{}})))
  61. if err != nil {
  62. bucketFactory.logger.Errorf("reset_filter debug error : %s", err)
  63. return err
  64. }
  65. }
  66. return err
  67. }