Revert "use expr func"

This reverts commit ac451ccaf3.
This commit is contained in:
Sebastien Blot 2023-12-04 21:00:19 +01:00
parent ac451ccaf3
commit e637e7bf8b
No known key found for this signature in database
GPG key ID: DFC2902F40449F6A
7 changed files with 253 additions and 503 deletions

View file

@ -6,438 +6,438 @@ import (
"github.com/crowdsecurity/crowdsec/pkg/cticlient" "github.com/crowdsecurity/crowdsec/pkg/cticlient"
) )
type ExprCustomFunc struct { type exprCustomFunc struct {
Name string name string
Function func(params ...any) (any, error) function func(params ...any) (any, error)
Signature []interface{} signature []interface{}
} }
var exprFuncs = []ExprCustomFunc{ var exprFuncs = []exprCustomFunc{
{ {
Name: "CrowdsecCTI", name: "CrowdsecCTI",
Function: CrowdsecCTI, function: CrowdsecCTI,
Signature: []interface{}{ signature: []interface{}{
new(func(string) (*cticlient.SmokeItem, error)), new(func(string) (*cticlient.SmokeItem, error)),
}, },
}, },
{ {
Name: "Flatten", name: "Flatten",
Function: Flatten, function: Flatten,
Signature: []interface{}{}, signature: []interface{}{},
}, },
{ {
Name: "Distinct", name: "Distinct",
Function: Distinct, function: Distinct,
Signature: []interface{}{}, signature: []interface{}{},
}, },
{ {
Name: "FlattenDistinct", name: "FlattenDistinct",
Function: FlattenDistinct, function: FlattenDistinct,
Signature: []interface{}{}, signature: []interface{}{},
}, },
{ {
Name: "Distance", name: "Distance",
Function: Distance, function: Distance,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string, string, string) (float64, error)), new(func(string, string, string, string) (float64, error)),
}, },
}, },
{ {
Name: "GetFromStash", name: "GetFromStash",
Function: GetFromStash, function: GetFromStash,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) (string, error)), new(func(string, string) (string, error)),
}, },
}, },
{ {
Name: "Atof", name: "Atof",
Function: Atof, function: Atof,
Signature: []interface{}{ signature: []interface{}{
new(func(string) float64), new(func(string) float64),
}, },
}, },
{ {
Name: "JsonExtract", name: "JsonExtract",
Function: JsonExtract, function: JsonExtract,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) string), new(func(string, string) string),
}, },
}, },
{ {
Name: "JsonExtractUnescape", name: "JsonExtractUnescape",
Function: JsonExtractUnescape, function: JsonExtractUnescape,
Signature: []interface{}{ signature: []interface{}{
new(func(string, ...string) string), new(func(string, ...string) string),
}, },
}, },
{ {
Name: "JsonExtractLib", name: "JsonExtractLib",
Function: JsonExtractLib, function: JsonExtractLib,
Signature: []interface{}{ signature: []interface{}{
new(func(string, ...string) string), new(func(string, ...string) string),
}, },
}, },
{ {
Name: "JsonExtractSlice", name: "JsonExtractSlice",
Function: JsonExtractSlice, function: JsonExtractSlice,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) []interface{}), new(func(string, string) []interface{}),
}, },
}, },
{ {
Name: "JsonExtractObject", name: "JsonExtractObject",
Function: JsonExtractObject, function: JsonExtractObject,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) map[string]interface{}), new(func(string, string) map[string]interface{}),
}, },
}, },
{ {
Name: "ToJsonString", name: "ToJsonString",
Function: ToJson, function: ToJson,
Signature: []interface{}{ signature: []interface{}{
new(func(interface{}) string), new(func(interface{}) string),
}, },
}, },
{ {
Name: "File", name: "File",
Function: File, function: File,
Signature: []interface{}{ signature: []interface{}{
new(func(string) []string), new(func(string) []string),
}, },
}, },
{ {
Name: "RegexpInFile", name: "RegexpInFile",
Function: RegexpInFile, function: RegexpInFile,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) bool), new(func(string, string) bool),
}, },
}, },
{ {
Name: "Upper", name: "Upper",
Function: Upper, function: Upper,
Signature: []interface{}{ signature: []interface{}{
new(func(string) string), new(func(string) string),
}, },
}, },
{ {
Name: "Lower", name: "Lower",
Function: Lower, function: Lower,
Signature: []interface{}{ signature: []interface{}{
new(func(string) string), new(func(string) string),
}, },
}, },
{ {
Name: "IpInRange", name: "IpInRange",
Function: IpInRange, function: IpInRange,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) bool), new(func(string, string) bool),
}, },
}, },
{ {
Name: "TimeNow", name: "TimeNow",
Function: TimeNow, function: TimeNow,
Signature: []interface{}{ signature: []interface{}{
new(func() string), new(func() string),
}, },
}, },
{ {
Name: "ParseUri", name: "ParseUri",
Function: ParseUri, function: ParseUri,
Signature: []interface{}{ signature: []interface{}{
new(func(string) map[string][]string), new(func(string) map[string][]string),
}, },
}, },
{ {
Name: "PathUnescape", name: "PathUnescape",
Function: PathUnescape, function: PathUnescape,
Signature: []interface{}{ signature: []interface{}{
new(func(string) string), new(func(string) string),
}, },
}, },
{ {
Name: "QueryUnescape", name: "QueryUnescape",
Function: QueryUnescape, function: QueryUnescape,
Signature: []interface{}{ signature: []interface{}{
new(func(string) string), new(func(string) string),
}, },
}, },
{ {
Name: "PathEscape", name: "PathEscape",
Function: PathEscape, function: PathEscape,
Signature: []interface{}{ signature: []interface{}{
new(func(string) string), new(func(string) string),
}, },
}, },
{ {
Name: "QueryEscape", name: "QueryEscape",
Function: QueryEscape, function: QueryEscape,
Signature: []interface{}{ signature: []interface{}{
new(func(string) string), new(func(string) string),
}, },
}, },
{ {
Name: "XMLGetAttributeValue", name: "XMLGetAttributeValue",
Function: XMLGetAttributeValue, function: XMLGetAttributeValue,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string, string) string), new(func(string, string, string) string),
}, },
}, },
{ {
Name: "XMLGetNodeValue", name: "XMLGetNodeValue",
Function: XMLGetNodeValue, function: XMLGetNodeValue,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) string), new(func(string, string) string),
}, },
}, },
{ {
Name: "IpToRange", name: "IpToRange",
Function: IpToRange, function: IpToRange,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) string), new(func(string, string) string),
}, },
}, },
{ {
Name: "IsIPV6", name: "IsIPV6",
Function: IsIPV6, function: IsIPV6,
Signature: []interface{}{ signature: []interface{}{
new(func(string) bool), new(func(string) bool),
}, },
}, },
{ {
Name: "IsIPV4", name: "IsIPV4",
Function: IsIPV4, function: IsIPV4,
Signature: []interface{}{ signature: []interface{}{
new(func(string) bool), new(func(string) bool),
}, },
}, },
{ {
Name: "IsIP", name: "IsIP",
Function: IsIP, function: IsIP,
Signature: []interface{}{ signature: []interface{}{
new(func(string) bool), new(func(string) bool),
}, },
}, },
{ {
Name: "LookupHost", name: "LookupHost",
Function: LookupHost, function: LookupHost,
Signature: []interface{}{ signature: []interface{}{
new(func(string) []string), new(func(string) []string),
}, },
}, },
{ {
Name: "GetDecisionsCount", name: "GetDecisionsCount",
Function: GetDecisionsCount, function: GetDecisionsCount,
Signature: []interface{}{ signature: []interface{}{
new(func(string) int), new(func(string) int),
}, },
}, },
{ {
Name: "GetDecisionsSinceCount", name: "GetDecisionsSinceCount",
Function: GetDecisionsSinceCount, function: GetDecisionsSinceCount,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) int), new(func(string, string) int),
}, },
}, },
{ {
Name: "Sprintf", name: "Sprintf",
Function: Sprintf, function: Sprintf,
Signature: []interface{}{ signature: []interface{}{
new(func(string, ...interface{}) string), new(func(string, ...interface{}) string),
}, },
}, },
{ {
Name: "ParseUnix", name: "ParseUnix",
Function: ParseUnix, function: ParseUnix,
Signature: []interface{}{ signature: []interface{}{
new(func(string) string), new(func(string) string),
}, },
}, },
{ {
Name: "SetInStash", //FIXME: signature will probably blow everything up name: "SetInStash", //FIXME: signature will probably blow everything up
Function: SetInStash, function: SetInStash,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string, string, *time.Duration) error), new(func(string, string, string, *time.Duration) error),
}, },
}, },
{ {
Name: "Fields", name: "Fields",
Function: Fields, function: Fields,
Signature: []interface{}{ signature: []interface{}{
new(func(string) []string), new(func(string) []string),
}, },
}, },
{ {
Name: "Index", name: "Index",
Function: Index, function: Index,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) int), new(func(string, string) int),
}, },
}, },
{ {
Name: "IndexAny", name: "IndexAny",
Function: IndexAny, function: IndexAny,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) int), new(func(string, string) int),
}, },
}, },
{ {
Name: "Join", name: "Join",
Function: Join, function: Join,
Signature: []interface{}{ signature: []interface{}{
new(func([]string, string) string), new(func([]string, string) string),
}, },
}, },
{ {
Name: "Split", name: "Split",
Function: Split, function: Split,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) []string), new(func(string, string) []string),
}, },
}, },
{ {
Name: "SplitAfter", name: "SplitAfter",
Function: SplitAfter, function: SplitAfter,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) []string), new(func(string, string) []string),
}, },
}, },
{ {
Name: "SplitAfterN", name: "SplitAfterN",
Function: SplitAfterN, function: SplitAfterN,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string, int) []string), new(func(string, string, int) []string),
}, },
}, },
{ {
Name: "SplitN", name: "SplitN",
Function: SplitN, function: SplitN,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string, int) []string), new(func(string, string, int) []string),
}, },
}, },
{ {
Name: "Replace", name: "Replace",
Function: Replace, function: Replace,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string, string, int) string), new(func(string, string, string, int) string),
}, },
}, },
{ {
Name: "ReplaceAll", name: "ReplaceAll",
Function: ReplaceAll, function: ReplaceAll,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string, string) string), new(func(string, string, string) string),
}, },
}, },
{ {
Name: "Trim", name: "Trim",
Function: Trim, function: Trim,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) string), new(func(string, string) string),
}, },
}, },
{ {
Name: "TrimLeft", name: "TrimLeft",
Function: TrimLeft, function: TrimLeft,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) string), new(func(string, string) string),
}, },
}, },
{ {
Name: "TrimRight", name: "TrimRight",
Function: TrimRight, function: TrimRight,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) string), new(func(string, string) string),
}, },
}, },
{ {
Name: "TrimSpace", name: "TrimSpace",
Function: TrimSpace, function: TrimSpace,
Signature: []interface{}{ signature: []interface{}{
new(func(string) string), new(func(string) string),
}, },
}, },
{ {
Name: "TrimPrefix", name: "TrimPrefix",
Function: TrimPrefix, function: TrimPrefix,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) string), new(func(string, string) string),
}, },
}, },
{ {
Name: "TrimSuffix", name: "TrimSuffix",
Function: TrimSuffix, function: TrimSuffix,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) string), new(func(string, string) string),
}, },
}, },
{ {
Name: "Get", name: "Get",
Function: Get, function: Get,
Signature: []interface{}{ signature: []interface{}{
new(func([]string, int) string), new(func([]string, int) string),
}, },
}, },
{ {
Name: "ToString", name: "ToString",
Function: ToString, function: ToString,
Signature: []interface{}{ signature: []interface{}{
new(func(interface{}) string), new(func(interface{}) string),
}, },
}, },
{ {
Name: "Match", name: "Match",
Function: Match, function: Match,
Signature: []interface{}{ signature: []interface{}{
new(func(string, string) bool), new(func(string, string) bool),
}, },
}, },
{ {
Name: "KeyExists", name: "KeyExists",
Function: KeyExists, function: KeyExists,
Signature: []interface{}{ signature: []interface{}{
new(func(string, map[string]any) bool), new(func(string, map[string]any) bool),
}, },
}, },
{ {
Name: "LogInfo", name: "LogInfo",
Function: LogInfo, function: LogInfo,
Signature: []interface{}{ signature: []interface{}{
new(func(string, ...interface{}) bool), new(func(string, ...interface{}) bool),
}, },
}, },
{ {
Name: "B64Decode", name: "B64Decode",
Function: B64Decode, function: B64Decode,
Signature: []interface{}{ signature: []interface{}{
new(func(string) string), new(func(string) string),
}, },
}, },
{ {
Name: "UnmarshalJSON", name: "UnmarshalJSON",
Function: UnmarshalJSON, function: UnmarshalJSON,
Signature: []interface{}{ signature: []interface{}{
new(func(string, map[string]interface{}, string) error), new(func(string, map[string]interface{}, string) error),
}, },
}, },
{ {
Name: "ParseKV", name: "ParseKV",
Function: ParseKV, function: ParseKV,
Signature: []interface{}{ signature: []interface{}{
new(func(string, map[string]interface{}, string) error), new(func(string, map[string]interface{}, string) error),
}, },
}, },
{ {
Name: "Hostname", name: "Hostname",
Function: Hostname, function: Hostname,
Signature: []interface{}{ signature: []interface{}{
new(func() (string, error)), new(func() (string, error)),
}, },
}, },
{ {
Name: "FloatApproxEqual", name: "FloatApproxEqual",
Function: FloatApproxEqual, function: FloatApproxEqual,
Signature: []interface{}{ signature: []interface{}{
new(func(float64, float64) bool), new(func(float64, float64) bool),
}, },
}, },

View file

@ -60,9 +60,9 @@ func GetExprOptions(ctx map[string]interface{}) []expr.Option {
exprFunctionOptions = []expr.Option{} exprFunctionOptions = []expr.Option{}
for _, function := range exprFuncs { for _, function := range exprFuncs {
exprFunctionOptions = append(exprFunctionOptions, exprFunctionOptions = append(exprFunctionOptions,
expr.Function(function.Name, expr.Function(function.name,
function.Function, function.function,
function.Signature..., function.signature...,
)) ))
} }
} }

View file

@ -58,12 +58,12 @@ type ReqDumpFilter struct {
ArgsDrop bool ArgsDrop bool
} }
func (r *ParsedRequest) DumpRequest(params ...any) (any, error) { func (r *ParsedRequest) DumpRequest(params ...any) *ReqDumpFilter {
filter := ReqDumpFilter{} filter := ReqDumpFilter{}
filter.BodyDrop = true filter.BodyDrop = true
filter.HeadersNameFilters = []string{"cookie", "authorization"} filter.HeadersNameFilters = []string{"cookie", "authorization"}
filter.req = r filter.req = r
return &filter, nil return &filter
} }
// clear filters // clear filters

View file

@ -161,8 +161,7 @@ func TestBodyDumper(t *testing.T) {
for idx, test := range tests { for idx, test := range tests {
t.Run(test.name, func(t *testing.T) { t.Run(test.name, func(t *testing.T) {
tmp_dr, _ := test.req.DumpRequest() orig_dr := test.req.DumpRequest()
orig_dr := tmp_dr.(*ReqDumpFilter)
result := test.filter(orig_dr).GetFilteredRequest() result := test.filter(orig_dr).GetFilteredRequest()
if len(result.Body) != len(test.expect.Body) { if len(result.Body) != len(test.expect.Body) {

View file

@ -34,26 +34,19 @@ const (
func (h *Hook) Build(hookStage int) error { func (h *Hook) Build(hookStage int) error {
ctx := map[string]interface{}{} ctx := map[string]interface{}{}
opts := []expr.Option{}
switch hookStage { switch hookStage {
case hookOnLoad: case hookOnLoad:
opts = GetOnLoadEnv(ctx, &WaapRuntimeConfig{}) ctx = GetOnLoadEnv(&WaapRuntimeConfig{})
case hookPreEval: case hookPreEval:
ctx["IsInBand"] = true ctx = GetPreEvalEnv(&WaapRuntimeConfig{}, &ParsedRequest{})
ctx["IsOutBand"] = true
opts = GetPreEvalEnv(ctx, &WaapRuntimeConfig{}, &ParsedRequest{})
case hookPostEval: case hookPostEval:
ctx["IsInBand"] = true ctx = GetPostEvalEnv(&WaapRuntimeConfig{}, &ParsedRequest{})
ctx["IsOutBand"] = true
opts = GetPostEvalEnv(ctx, &WaapRuntimeConfig{}, &ParsedRequest{})
case hookOnMatch: case hookOnMatch:
ctx["evt"] = types.Event{} ctx = GetOnMatchEnv(&WaapRuntimeConfig{}, &ParsedRequest{}, types.Event{})
ctx["IsInBand"] = true
ctx["IsOutBand"] = true
opts = GetOnMatchEnv(ctx, &WaapRuntimeConfig{}, &ParsedRequest{})
} }
opts := GetExprWAFOptions(ctx)
if h.Filter != "" { if h.Filter != "" {
program, err := expr.Compile(h.Filter, opts...) program, err := expr.Compile(h.Filter, opts...) //FIXME: opts
if err != nil { if err != nil {
return fmt.Errorf("unable to compile filter %s : %w", h.Filter, err) return fmt.Errorf("unable to compile filter %s : %w", h.Filter, err)
} }
@ -290,7 +283,7 @@ func (wc *WaapConfig) Build() (*WaapRuntimeConfig, error) {
func (w *WaapRuntimeConfig) ProcessOnLoadRules() error { func (w *WaapRuntimeConfig) ProcessOnLoadRules() error {
for _, rule := range w.CompiledOnLoad { for _, rule := range w.CompiledOnLoad {
if rule.FilterExpr != nil { if rule.FilterExpr != nil {
output, err := exprhelpers.Run(rule.FilterExpr, map[string]interface{}{}, w.Logger, w.Logger.Level >= log.DebugLevel) output, err := exprhelpers.Run(rule.FilterExpr, GetOnLoadEnv(w), w.Logger, w.Logger.Level >= log.DebugLevel)
if err != nil { if err != nil {
return fmt.Errorf("unable to run waap on_load filter %s : %w", rule.Filter, err) return fmt.Errorf("unable to run waap on_load filter %s : %w", rule.Filter, err)
} }
@ -306,7 +299,7 @@ func (w *WaapRuntimeConfig) ProcessOnLoadRules() error {
} }
} }
for _, applyExpr := range rule.ApplyExpr { for _, applyExpr := range rule.ApplyExpr {
_, err := exprhelpers.Run(applyExpr, map[string]interface{}{}, w.Logger, w.Logger.Level >= log.DebugLevel) _, err := exprhelpers.Run(applyExpr, GetOnLoadEnv(w), w.Logger, w.Logger.Level >= log.DebugLevel)
if err != nil { if err != nil {
log.Errorf("unable to apply waap on_load expr: %s", err) log.Errorf("unable to apply waap on_load expr: %s", err)
continue continue
@ -317,14 +310,10 @@ func (w *WaapRuntimeConfig) ProcessOnLoadRules() error {
} }
func (w *WaapRuntimeConfig) ProcessOnMatchRules(request *ParsedRequest, evt types.Event) error { func (w *WaapRuntimeConfig) ProcessOnMatchRules(request *ParsedRequest, evt types.Event) error {
ctx := map[string]interface{}{
"evt": evt,
"IsInBand": request.IsInBand,
"IsOutBand": request.IsOutBand,
}
for _, rule := range w.CompiledOnMatch { for _, rule := range w.CompiledOnMatch {
if rule.FilterExpr != nil { if rule.FilterExpr != nil {
output, err := exprhelpers.Run(rule.FilterExpr, ctx, w.Logger, w.Logger.Level >= log.DebugLevel) output, err := exprhelpers.Run(rule.FilterExpr, GetOnMatchEnv(w, request, evt), w.Logger, w.Logger.Level >= log.DebugLevel)
if err != nil { if err != nil {
return fmt.Errorf("unable to run waap on_match filter %s : %w", rule.Filter, err) return fmt.Errorf("unable to run waap on_match filter %s : %w", rule.Filter, err)
} }
@ -340,7 +329,7 @@ func (w *WaapRuntimeConfig) ProcessOnMatchRules(request *ParsedRequest, evt type
} }
} }
for _, applyExpr := range rule.ApplyExpr { for _, applyExpr := range rule.ApplyExpr {
_, err := exprhelpers.Run(applyExpr, ctx, w.Logger, w.Logger.Level >= log.DebugLevel) _, err := exprhelpers.Run(applyExpr, GetOnMatchEnv(w, request, evt), w.Logger, w.Logger.Level >= log.DebugLevel)
if err != nil { if err != nil {
log.Errorf("unable to apply waap on_match expr: %s", err) log.Errorf("unable to apply waap on_match expr: %s", err)
continue continue
@ -351,13 +340,9 @@ func (w *WaapRuntimeConfig) ProcessOnMatchRules(request *ParsedRequest, evt type
} }
func (w *WaapRuntimeConfig) ProcessPreEvalRules(request *ParsedRequest) error { func (w *WaapRuntimeConfig) ProcessPreEvalRules(request *ParsedRequest) error {
ctx := map[string]interface{}{
"IsInBand": request.IsInBand,
"IsOutBand": request.IsOutBand,
}
for _, rule := range w.CompiledPreEval { for _, rule := range w.CompiledPreEval {
if rule.FilterExpr != nil { if rule.FilterExpr != nil {
output, err := exprhelpers.Run(rule.FilterExpr, GetPreEvalEnv(ctx, w, request), w.Logger, w.Logger.Level >= log.DebugLevel) output, err := exprhelpers.Run(rule.FilterExpr, GetPreEvalEnv(w, request), w.Logger, w.Logger.Level >= log.DebugLevel)
if err != nil { if err != nil {
return fmt.Errorf("unable to run waap pre_eval filter %s : %w", rule.Filter, err) return fmt.Errorf("unable to run waap pre_eval filter %s : %w", rule.Filter, err)
} }
@ -374,7 +359,7 @@ func (w *WaapRuntimeConfig) ProcessPreEvalRules(request *ParsedRequest) error {
} }
// here means there is no filter or the filter matched // here means there is no filter or the filter matched
for _, applyExpr := range rule.ApplyExpr { for _, applyExpr := range rule.ApplyExpr {
_, err := exprhelpers.Run(applyExpr, ctx, w.Logger, w.Logger.Level >= log.DebugLevel) _, err := exprhelpers.Run(applyExpr, GetPreEvalEnv(w, request), w.Logger, w.Logger.Level >= log.DebugLevel)
if err != nil { if err != nil {
log.Errorf("unable to apply waap pre_eval expr: %s", err) log.Errorf("unable to apply waap pre_eval expr: %s", err)
continue continue
@ -386,13 +371,9 @@ func (w *WaapRuntimeConfig) ProcessPreEvalRules(request *ParsedRequest) error {
} }
func (w *WaapRuntimeConfig) ProcessPostEvalRules(request *ParsedRequest) error { func (w *WaapRuntimeConfig) ProcessPostEvalRules(request *ParsedRequest) error {
ctx := map[string]interface{}{
"IsInBand": request.IsInBand,
"IsOutBand": request.IsOutBand,
}
for _, rule := range w.CompiledPostEval { for _, rule := range w.CompiledPostEval {
if rule.FilterExpr != nil { if rule.FilterExpr != nil {
output, err := exprhelpers.Run(rule.FilterExpr, ctx, w.Logger, w.Logger.Level >= log.DebugLevel) output, err := exprhelpers.Run(rule.FilterExpr, GetPostEvalEnv(w, request), w.Logger, w.Logger.Level >= log.DebugLevel)
if err != nil { if err != nil {
return fmt.Errorf("unable to run waap post_eval filter %s : %w", rule.Filter, err) return fmt.Errorf("unable to run waap post_eval filter %s : %w", rule.Filter, err)
} }
@ -409,7 +390,7 @@ func (w *WaapRuntimeConfig) ProcessPostEvalRules(request *ParsedRequest) error {
} }
// here means there is no filter or the filter matched // here means there is no filter or the filter matched
for _, applyExpr := range rule.ApplyExpr { for _, applyExpr := range rule.ApplyExpr {
_, err := exprhelpers.Run(applyExpr, ctx, w.Logger, w.Logger.Level >= log.DebugLevel) _, err := exprhelpers.Run(applyExpr, GetPostEvalEnv(w, request), w.Logger, w.Logger.Level >= log.DebugLevel)
if err != nil { if err != nil {
log.Errorf("unable to apply waap post_eval expr: %s", err) log.Errorf("unable to apply waap post_eval expr: %s", err)
continue continue
@ -570,7 +551,6 @@ func (w *WaapRuntimeConfig) SetActionByID(params ...any) (any, error) {
// func (w *WaapRuntimeConfig) SetActionByID(name string, action string) error { // func (w *WaapRuntimeConfig) SetActionByID(name string, action string) error {
func (w *WaapRuntimeConfig) SetActionByName(params ...any) (any, error) { func (w *WaapRuntimeConfig) SetActionByName(params ...any) (any, error) {
fmt.Printf("%v+\n", w)
if w.RemediationByTag == nil { if w.RemediationByTag == nil {
w.RemediationByTag = make(map[string]string) w.RemediationByTag = make(map[string]string)
} }

View file

@ -1,3 +1,11 @@
package waf package waf
//This is a copy paste from expr_lib.go, we probably want to only have one ? //This is a copy paste from expr_lib.go, we probably want to only have one ?
type exprCustomFunc struct {
name string
function func(params ...any) (any, error)
signature []interface{}
}
var exprFuncs = []exprCustomFunc{}

View file

@ -3,183 +3,40 @@ package waf
import ( import (
"github.com/antonmedv/expr" "github.com/antonmedv/expr"
"github.com/crowdsecurity/crowdsec/pkg/exprhelpers" "github.com/crowdsecurity/crowdsec/pkg/exprhelpers"
"github.com/crowdsecurity/crowdsec/pkg/types"
) )
var exprOnLoadOptions = []expr.Option{} func GetExprWAFOptions(ctx map[string]interface{}) []expr.Option {
var exprPreEvalOptions = []expr.Option{}
var exprPostEvalOptions = []expr.Option{}
var exprOnMatchOptions = []expr.Option{}
func GetOnLoadEnv(ctx map[string]interface{}, w *WaapRuntimeConfig) []expr.Option {
baseHelpers := exprhelpers.GetExprOptions(ctx) baseHelpers := exprhelpers.GetExprOptions(ctx)
onLoadHelpers := []exprhelpers.ExprCustomFunc{
{
Name: "RemoveInBandRuleByID",
Function: w.DisableInBandRuleByID,
Signature: []interface{}{
new(func(int) error),
},
},
{
Name: "RemoveInBandRuleByTag",
Function: w.DisableInBandRuleByTag,
Signature: []interface{}{
new(func(string) error),
},
},
{
Name: "RemoveInBandRuleByName",
Function: w.DisableInBandRuleByName,
Signature: []interface{}{
new(func(string) error),
},
},
{
Name: "RemoveOutBandRuleByID",
Function: w.DisableOutBandRuleByID,
Signature: []interface{}{
new(func(int) error),
},
},
{
Name: "RemoveOutBandRuleByTag",
Function: w.DisableOutBandRuleByTag,
Signature: []interface{}{
new(func(string) error),
},
},
{
Name: "RemoveOutBandRuleByName",
Function: w.DisableOutBandRuleByName,
Signature: []interface{}{
new(func(string) error),
},
},
{
Name: "SetRemediationByTag",
Function: w.SetActionByTag,
Signature: []interface{}{
new(func(string, string) error),
},
},
{
Name: "SetRemediationByID",
Function: w.SetActionByID,
Signature: []interface{}{
new(func(int, string) error),
},
},
{
Name: "SetRemediationByName",
Function: w.SetActionByName,
Signature: []interface{}{
new(func(string, string) error),
},
},
}
if len(exprOnLoadOptions) == 0 { for _, function := range exprFuncs {
for _, function := range onLoadHelpers { baseHelpers = append(baseHelpers,
exprOnLoadOptions = append(exprOnLoadOptions, expr.Function(function.name,
expr.Function( function.function,
function.Name, function.signature...,
function.Function, ))
function.Signature...,
),
)
} }
exprOnLoadOptions = append(exprOnLoadOptions, baseHelpers...) return baseHelpers
}
return exprOnLoadOptions
} }
func GetPreEvalEnv(ctx map[string]interface{}, w *WaapRuntimeConfig, request *ParsedRequest) []expr.Option { func GetOnLoadEnv(w *WaapRuntimeConfig) map[string]interface{} {
baseHelpers := exprhelpers.GetExprOptions(ctx)
preEvalHelpers := []exprhelpers.ExprCustomFunc{
{
Name: "RemoveInBandRuleByID",
Function: w.RemoveInbandRuleByID,
Signature: []interface{}{
new(func(int) error),
},
},
{
Name: "RemoveInBandRuleByTag",
Function: w.RemoveInbandRuleByTag,
Signature: []interface{}{
new(func(string) error),
},
},
{
Name: "RemoveInBandRuleByName",
Function: w.RemoveInbandRuleByName,
Signature: []interface{}{
new(func(string) error),
},
},
{
Name: "RemoveOutBandRuleByID",
Function: w.RemoveOutbandRuleByID,
Signature: []interface{}{
new(func(int) error),
},
},
{
Name: "RemoveOutBandRuleByTag",
Function: w.RemoveOutbandRuleByTag,
Signature: []interface{}{
new(func(string) error),
},
},
{
Name: "RemoveOutBandRuleByName",
Function: w.RemoveOutbandRuleByName,
Signature: []interface{}{
new(func(string) error),
},
},
{
Name: "SetRemediationByTag",
Function: w.SetActionByTag,
Signature: []interface{}{
new(func(string, string) error),
},
},
{
Name: "SetRemediationByID",
Function: w.SetActionByID,
Signature: []interface{}{
new(func(int, string) error),
},
},
{
Name: "SetRemediationByName",
Function: w.SetActionByName,
Signature: []interface{}{
new(func(string, string) error),
},
},
}
if len(exprPreEvalOptions) == 0 {
for _, function := range preEvalHelpers {
exprPreEvalOptions = append(exprPreEvalOptions,
expr.Function(
function.Name,
function.Function,
function.Signature...,
),
)
}
exprPreEvalOptions = append(exprPreEvalOptions, baseHelpers...)
}
return exprPreEvalOptions
//FIXME: use expr.Function instead of this //FIXME: use expr.Function instead of this
/*return map[string]interface{}{ return map[string]interface{}{
"RemoveInBandRuleByID": w.DisableInBandRuleByID,
"RemoveInBandRuleByTag": w.DisableInBandRuleByTag,
"RemoveInBandRuleByName": w.DisableInBandRuleByName,
"RemoveOutBandRuleByID": w.DisableOutBandRuleByID,
"RemoveOutBandRuleByTag": w.DisableOutBandRuleByTag,
"RemoveOutBandRuleByName": w.DisableOutBandRuleByName,
"SetRemediationByTag": w.SetActionByTag,
"SetRemediationByID": w.SetActionByID,
"SetRemediationByName": w.SetActionByName,
}
}
func GetPreEvalEnv(w *WaapRuntimeConfig, request *ParsedRequest) map[string]interface{} {
//FIXME: use expr.Function instead of this
return map[string]interface{}{
"IsInBand": request.IsInBand, "IsInBand": request.IsInBand,
"IsOutBand": request.IsOutBand, "IsOutBand": request.IsOutBand,
"RemoveInBandRuleByID": w.RemoveInbandRuleByID, "RemoveInBandRuleByID": w.RemoveInbandRuleByID,
@ -191,114 +48,20 @@ func GetPreEvalEnv(ctx map[string]interface{}, w *WaapRuntimeConfig, request *Pa
"SetRemediationByTag": w.SetActionByTag, "SetRemediationByTag": w.SetActionByTag,
"SetRemediationByID": w.SetActionByID, "SetRemediationByID": w.SetActionByID,
"SetRemediationByName": w.SetActionByName, "SetRemediationByName": w.SetActionByName,
}*/ }
} }
func GetPostEvalEnv(ctx map[string]interface{}, w *WaapRuntimeConfig, request *ParsedRequest) []expr.Option { func GetPostEvalEnv(w *WaapRuntimeConfig, request *ParsedRequest) map[string]interface{} {
baseHelpers := exprhelpers.GetExprOptions(ctx) //FIXME: use expr.Function instead of this
postEvalHelpers := []exprhelpers.ExprCustomFunc{
{
Name: "DumpRequest",
Function: request.DumpRequest,
Signature: []interface{}{
new(func() *ReqDumpFilter),
},
},
}
if len(exprPostEvalOptions) == 0 {
for _, function := range postEvalHelpers {
exprPostEvalOptions = append(exprPostEvalOptions,
expr.Function(
function.Name,
function.Function,
function.Signature...,
),
)
}
exprPostEvalOptions = append(exprPostEvalOptions, baseHelpers...)
}
return exprPostEvalOptions
/*//FIXME: use expr.Function instead of this
return map[string]interface{}{ return map[string]interface{}{
"IsInBand": request.IsInBand, "IsInBand": request.IsInBand,
"IsOutBand": request.IsOutBand, "IsOutBand": request.IsOutBand,
"DumpRequest": request.DumpRequest, "DumpRequest": request.DumpRequest,
}*/ }
} }
func GetOnMatchEnv(ctx map[string]interface{}, w *WaapRuntimeConfig, request *ParsedRequest) []expr.Option { func GetOnMatchEnv(w *WaapRuntimeConfig, request *ParsedRequest, evt types.Event) map[string]interface{} {
baseHelpers := exprhelpers.GetExprOptions(ctx) //FIXME: use expr.Function instead of this
onMatchHelpers := []exprhelpers.ExprCustomFunc{
{
Name: "SetRemediation",
Function: w.SetAction,
Signature: []interface{}{
new(func(string) error),
},
},
{
Name: "SetReturnCode",
Function: w.SetHTTPCode,
Signature: []interface{}{
new(func(int) error),
},
},
{
Name: "CancelEvent",
Function: w.CancelEvent,
Signature: []interface{}{
new(func() error),
},
},
{
Name: "SendEvent",
Function: w.SendEvent,
Signature: []interface{}{
new(func() error),
},
},
{
Name: "CancelAlert",
Function: w.CancelAlert,
Signature: []interface{}{
new(func() error),
},
},
{
Name: "SendAlert",
Function: w.SendAlert,
Signature: []interface{}{
new(func() error),
},
},
{
Name: "DumpRequest",
Function: request.DumpRequest,
Signature: []interface{}{
new(func() *ReqDumpFilter),
},
},
}
if len(exprOnMatchOptions) == 0 {
for _, function := range onMatchHelpers {
exprOnMatchOptions = append(exprOnMatchOptions,
expr.Function(
function.Name,
function.Function,
function.Signature...,
),
)
}
exprOnMatchOptions = append(exprOnMatchOptions, baseHelpers...)
}
return exprOnMatchOptions
/*//FIXME: use expr.Function instead of this
return map[string]interface{}{ return map[string]interface{}{
"evt": evt, "evt": evt,
"req": request, "req": request,
@ -311,5 +74,5 @@ func GetOnMatchEnv(ctx map[string]interface{}, w *WaapRuntimeConfig, request *Pa
"CancelAlert": w.CancelAlert, "CancelAlert": w.CancelAlert,
"SendAlert": w.SendAlert, "SendAlert": w.SendAlert,
"DumpRequest": request.DumpRequest, "DumpRequest": request.DumpRequest,
}*/ }
} }