Fix overflows of overflows requesting for different decision scope (#499)
This commit is contained in:
parent
8707140fb2
commit
2e76097d35
5 changed files with 71 additions and 13 deletions
|
@ -3,6 +3,7 @@ package csprofiles
|
|||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/antonmedv/expr"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/csconfig"
|
||||
|
@ -45,14 +46,15 @@ func GenerateDecisionFromProfile(Profile *csconfig.ProfileCfg, Alert *models.Ale
|
|||
decision.Value = new(string)
|
||||
*decision.Value = *Alert.Source.Value
|
||||
|
||||
if *decision.Scope == types.Ip {
|
||||
if strings.EqualFold(*decision.Scope, types.Ip) {
|
||||
srcAddr := net.ParseIP(Alert.Source.IP)
|
||||
if srcAddr == nil {
|
||||
return nil, fmt.Errorf("can't parse ip %s", Alert.Source.IP)
|
||||
}
|
||||
decision.StartIP = int64(types.IP2Int(srcAddr))
|
||||
decision.EndIP = decision.StartIP
|
||||
} else if *decision.Scope == types.Range {
|
||||
} else if strings.EqualFold(*decision.Scope, types.Range) {
|
||||
|
||||
/*here we're asked to ban a full range. let's keep in mind that it's not always possible :
|
||||
- the alert is about an IP, but the geolite enrichment failed
|
||||
- the alert is about an IP, but the geolite enrichment isn't present
|
||||
|
@ -108,6 +110,7 @@ func EvaluateProfiles(Profiles []*csconfig.ProfileCfg, Alert *models.Alert) ([]*
|
|||
}
|
||||
PROFILE_LOOP:
|
||||
for _, profile := range Profiles {
|
||||
matched := false
|
||||
for eIdx, expression := range profile.RuntimeFilters {
|
||||
output, err := expr.Run(expression, exprhelpers.GetExprEnv(map[string]interface{}{"Alert": Alert}))
|
||||
if err != nil {
|
||||
|
@ -117,11 +120,13 @@ PROFILE_LOOP:
|
|||
switch out := output.(type) {
|
||||
case bool:
|
||||
if out {
|
||||
matched = true
|
||||
/*the expression matched, create the associated decision*/
|
||||
subdecisions, err := GenerateDecisionFromProfile(profile, Alert)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "while generating decision from profile %s", profile.Name)
|
||||
}
|
||||
|
||||
decisions = append(decisions, subdecisions...)
|
||||
} else {
|
||||
if profile.Debug != nil && *profile.Debug {
|
||||
|
@ -132,10 +137,14 @@ PROFILE_LOOP:
|
|||
break PROFILE_LOOP
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected type %t (%v) while running '%s'", output, output, profile.Filters[eIdx])
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if matched {
|
||||
if profile.OnSuccess == "break" {
|
||||
break PROFILE_LOOP
|
||||
}
|
||||
|
|
|
@ -115,9 +115,6 @@ func (c *Client) CreateAlert(machineID string, alertList []*models.Alert) ([]str
|
|||
}
|
||||
|
||||
func (c *Client) CreateAlertBulk(machineId string, alertList []*models.Alert) ([]string, error) {
|
||||
var decisions []*ent.Decision
|
||||
var metas []*ent.Meta
|
||||
var events []*ent.Event
|
||||
|
||||
ret := []string{}
|
||||
bulkSize := 20
|
||||
|
@ -125,6 +122,10 @@ func (c *Client) CreateAlertBulk(machineId string, alertList []*models.Alert) ([
|
|||
c.Log.Debugf("writting %d items", len(alertList))
|
||||
bulk := make([]*ent.AlertCreate, 0, bulkSize)
|
||||
for i, alertItem := range alertList {
|
||||
var decisions []*ent.Decision
|
||||
var metas []*ent.Meta
|
||||
var events []*ent.Event
|
||||
|
||||
owner, err := c.QueryMachineByID(machineId)
|
||||
if err != nil {
|
||||
if errors.Cause(err) != UserNotExists {
|
||||
|
@ -212,6 +213,7 @@ func (c *Client) CreateAlertBulk(machineId string, alertList []*models.Alert) ([
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
alertB := c.Ent.Alert.
|
||||
Create().
|
||||
SetScenario(*alertItem.Scenario).
|
||||
|
@ -245,7 +247,7 @@ func (c *Client) CreateAlertBulk(machineId string, alertList []*models.Alert) ([
|
|||
if len(bulk) == bulkSize {
|
||||
alerts, err := c.Ent.Alert.CreateBulk(bulk...).Save(c.CTX)
|
||||
if err != nil {
|
||||
return []string{}, errors.Wrapf(BulkError, "creating alert : %s", err)
|
||||
return []string{}, errors.Wrapf(BulkError, "bulk creating alert : %s", err)
|
||||
}
|
||||
for _, alert := range alerts {
|
||||
ret = append(ret, strconv.Itoa(alert.ID))
|
||||
|
@ -261,7 +263,7 @@ func (c *Client) CreateAlertBulk(machineId string, alertList []*models.Alert) ([
|
|||
|
||||
alerts, err := c.Ent.Alert.CreateBulk(bulk...).Save(c.CTX)
|
||||
if err != nil {
|
||||
return []string{}, errors.Wrapf(BulkError, "creating alert : %s", err)
|
||||
return []string{}, errors.Wrapf(BulkError, "leftovers creating alert : %s", err)
|
||||
}
|
||||
|
||||
for _, alert := range alerts {
|
||||
|
|
|
@ -114,7 +114,7 @@ again the expr environment given in parameter
|
|||
*/
|
||||
func (e *ExprDebugger) Run(logger *logrus.Entry, filterResult bool, exprEnv map[string]interface{}) {
|
||||
if len(e.expression) == 0 {
|
||||
logger.Debugf("no variable to eval for filter '%s'", e.filter)
|
||||
logger.Tracef("no variable to eval for filter '%s'", e.filter)
|
||||
return
|
||||
}
|
||||
logger.Debugf("eval(%s) = %s", e.filter, strings.ToUpper(strconv.FormatBool(filterResult)))
|
||||
|
|
|
@ -18,12 +18,47 @@ import (
|
|||
|
||||
//SourceFromEvent extracts and formats a valid models.Source object from an Event
|
||||
func SourceFromEvent(evt types.Event, leaky *Leaky) (map[string]models.Source, error) {
|
||||
src := models.Source{}
|
||||
srcs := make(map[string]models.Source)
|
||||
|
||||
/*if it's already an overflow, we have properly formatted sources.
|
||||
we can just twitch them to reflect the requested scope*/
|
||||
if evt.Type == types.OVFLW {
|
||||
return evt.Overflow.Sources, nil
|
||||
|
||||
for k, v := range evt.Overflow.Sources {
|
||||
|
||||
/*the scopes are already similar, nothing to do*/
|
||||
if leaky.scopeType.Scope == *v.Scope {
|
||||
srcs[k] = v
|
||||
continue
|
||||
}
|
||||
|
||||
/*The bucket requires a decision on scope Range */
|
||||
if leaky.scopeType.Scope == types.Range {
|
||||
/*the original bucket was target IPs, check that we do have range*/
|
||||
if *v.Scope == types.Ip {
|
||||
if v.Range != "" {
|
||||
src := models.Source{}
|
||||
src.AsName = v.AsName
|
||||
src.AsNumber = v.AsNumber
|
||||
src.Cn = v.Cn
|
||||
src.Latitude = v.Latitude
|
||||
src.Longitude = v.Longitude
|
||||
src.Range = v.Range
|
||||
src.Value = new(string)
|
||||
src.Scope = new(string)
|
||||
*src.Value = v.Range
|
||||
*src.Scope = leaky.scopeType.Scope
|
||||
srcs[*src.Value] = src
|
||||
}
|
||||
} else {
|
||||
log.Warningf("bucket %s requires scope Range, but can't extrapolate from %s (%s)",
|
||||
leaky.Name, *v.Scope, *v.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
return srcs, nil
|
||||
}
|
||||
src := models.Source{}
|
||||
switch leaky.scopeType.Scope {
|
||||
case types.Range, types.Ip:
|
||||
if v, ok := evt.Meta["source_ip"]; ok {
|
||||
|
@ -74,7 +109,7 @@ func SourceFromEvent(evt types.Event, leaky *Leaky) (map[string]models.Source, e
|
|||
} else if leaky.scopeType.Scope == types.Range {
|
||||
src.Value = &src.Range
|
||||
}
|
||||
srcs[src.IP] = src
|
||||
srcs[*src.Value] = src
|
||||
default:
|
||||
if leaky.scopeType.RunTimeFilter != nil {
|
||||
retValue, err := expr.Run(leaky.scopeType.RunTimeFilter, exprhelpers.GetExprEnv(map[string]interface{}{"evt": &evt}))
|
||||
|
@ -90,7 +125,6 @@ func SourceFromEvent(evt types.Event, leaky *Leaky) (map[string]models.Source, e
|
|||
src.Scope = new(string)
|
||||
*src.Scope = leaky.scopeType.Scope
|
||||
srcs[*src.Value] = src
|
||||
log.Debugf("source[%s] - %s = %s", leaky.Name, leaky.scopeType.Scope, *src.Value)
|
||||
} else {
|
||||
return srcs, fmt.Errorf("empty scope information")
|
||||
}
|
||||
|
@ -213,7 +247,7 @@ func NewAlert(leaky *Leaky, queue *Queue) (types.RuntimeAlert, error) {
|
|||
//Include source info in format string
|
||||
sourceStr := ""
|
||||
if len(sources) > 1 {
|
||||
sourceStr = fmt.Sprintf("%d Sources on scope.", len(sources))
|
||||
sourceStr = fmt.Sprintf("%d sources", len(sources))
|
||||
} else if len(sources) == 1 {
|
||||
for k, _ := range sources {
|
||||
sourceStr = k
|
||||
|
|
|
@ -3,6 +3,8 @@ package types
|
|||
import (
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/antonmedv/expr/vm"
|
||||
"github.com/crowdsecurity/crowdsec/pkg/models"
|
||||
)
|
||||
|
@ -38,6 +40,17 @@ type Event struct {
|
|||
Meta map[string]string `yaml:"Meta,omitempty" json:"Meta,omitempty"`
|
||||
}
|
||||
|
||||
func (e *Event) GetType() string {
|
||||
if e.Type == OVFLW {
|
||||
return "overflow"
|
||||
} else if e.Type == LOG {
|
||||
return "log"
|
||||
} else {
|
||||
log.Warningf("unknown event type for %+v", e)
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
//Move in leakybuckets
|
||||
const (
|
||||
Undefined = ""
|
||||
|
|
Loading…
Reference in a new issue