github.com/crowdsecurity/crowdsec@v1.6.1/pkg/leakybucket/reset_filter.go (about) 1 package leakybucket 2 3 import ( 4 "sync" 5 6 "github.com/antonmedv/expr" 7 "github.com/antonmedv/expr/vm" 8 9 "github.com/crowdsecurity/crowdsec/pkg/exprhelpers" 10 "github.com/crowdsecurity/crowdsec/pkg/types" 11 ) 12 13 // ResetFilter allows to kill the bucket (without overflowing), if a particular condition is met. 14 // An example would be a scenario to detect aggressive crawlers that *do not* fetch any static resources : 15 // type : leaky 16 // filter: "evt.Meta.log_type == 'http_access-log' 17 // reset_filter: evt.Parsed.request endswith '.css' 18 // .... 19 // Thus, if the bucket receives a request that matches fetching a static resource (here css), it cancels itself 20 21 type CancelOnFilter struct { 22 CancelOnFilter *vm.Program 23 Debug bool 24 } 25 26 var cancelExprCacheLock sync.Mutex 27 var cancelExprCache map[string]struct { 28 CancelOnFilter *vm.Program 29 } 30 31 func (u *CancelOnFilter) OnBucketPour(bucketFactory *BucketFactory) func(types.Event, *Leaky) *types.Event { 32 return func(msg types.Event, leaky *Leaky) *types.Event { 33 var condition, ok bool 34 if u.CancelOnFilter != nil { 35 leaky.logger.Tracef("running cancel_on filter") 36 output, err := exprhelpers.Run(u.CancelOnFilter, map[string]interface{}{"evt": &msg}, leaky.logger, u.Debug) 37 if err != nil { 38 leaky.logger.Warningf("cancel_on error : %s", err) 39 return &msg 40 } 41 if condition, ok = output.(bool); !ok { 42 leaky.logger.Warningf("cancel_on, unexpected non-bool return : %T", output) 43 return &msg 44 } 45 if condition { 46 leaky.logger.Debugf("reset_filter matched, kill bucket") 47 leaky.Suicide <- true 48 return nil //counter intuitively, we need to keep the message so that it doesn't trigger an endless loop 49 } 50 leaky.logger.Debugf("reset_filter didn't match") 51 } 52 return &msg 53 } 54 } 55 56 func (u *CancelOnFilter) OnBucketOverflow(bucketFactory *BucketFactory) func(*Leaky, types.RuntimeAlert, *types.Queue) (types.RuntimeAlert, *types.Queue) { 57 return func(leaky *Leaky, alert types.RuntimeAlert, queue *types.Queue) (types.RuntimeAlert, *types.Queue) { 58 return alert, queue 59 } 60 } 61 62 func (u *CancelOnFilter) AfterBucketPour(bucketFactory *BucketFactory) func(types.Event, *Leaky) *types.Event { 63 return func(msg types.Event, leaky *Leaky) *types.Event { 64 return &msg 65 } 66 } 67 68 func (u *CancelOnFilter) OnBucketInit(bucketFactory *BucketFactory) error { 69 var err error 70 var compiledExpr struct { 71 CancelOnFilter *vm.Program 72 } 73 74 if cancelExprCache == nil { 75 cancelExprCache = make(map[string]struct { 76 CancelOnFilter *vm.Program 77 }) 78 } 79 80 cancelExprCacheLock.Lock() 81 if compiled, ok := cancelExprCache[bucketFactory.CancelOnFilter]; ok { 82 cancelExprCacheLock.Unlock() 83 u.CancelOnFilter = compiled.CancelOnFilter 84 return nil 85 } else { 86 cancelExprCacheLock.Unlock() 87 //release the lock during compile 88 89 compiledExpr.CancelOnFilter, err = expr.Compile(bucketFactory.CancelOnFilter, exprhelpers.GetExprOptions(map[string]interface{}{"evt": &types.Event{}})...) 90 if err != nil { 91 bucketFactory.logger.Errorf("reset_filter compile error : %s", err) 92 return err 93 } 94 u.CancelOnFilter = compiledExpr.CancelOnFilter 95 if bucketFactory.Debug { 96 u.Debug = true 97 } 98 cancelExprCacheLock.Lock() 99 cancelExprCache[bucketFactory.CancelOnFilter] = compiledExpr 100 cancelExprCacheLock.Unlock() 101 } 102 return err 103 }