* Improve whitelist parsing * Split whitelist check into a function tied to whitelist, also since we check node debug we can make a pointer to node containing whitelist * No point passing clog as an argument since it is just a pointer to node we already know about * We should break instead of returning false, false as it may have been whitelisted by ips/cidrs * reimplement early return if expr errors * Fix lint and dont need to parse ip back to string just loop over sources * Log error with node logger as it provides context * Move getsource to a function cleanup some code * Change func name * Split out compile to a function so we can use in tests. Add a bunch of tests * spell correction * Use node logger so it has context * alternative solution * quick fixes * Use containswls * Change whitelist test to use parseipsource and only events * Make it simpler * Postoverflow tests, some basic ones to make sure it works * Use official pkg * Add @mmetc reco * Add @mmetc reco * Change if if to a switch to only evaluate once * simplify assertions --------- Co-authored-by: bui <thibault@crowdsec.net> Co-authored-by: Marco Mariani <marco@crowdsec.net>
136 lines
3.8 KiB
Go
136 lines
3.8 KiB
Go
package parser
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
|
|
"github.com/antonmedv/expr"
|
|
"github.com/antonmedv/expr/vm"
|
|
|
|
"github.com/crowdsecurity/crowdsec/pkg/exprhelpers"
|
|
"github.com/crowdsecurity/crowdsec/pkg/types"
|
|
)
|
|
|
|
type Whitelist struct {
|
|
Reason string `yaml:"reason,omitempty"`
|
|
Ips []string `yaml:"ip,omitempty"`
|
|
B_Ips []net.IP
|
|
Cidrs []string `yaml:"cidr,omitempty"`
|
|
B_Cidrs []*net.IPNet
|
|
Exprs []string `yaml:"expression,omitempty"`
|
|
B_Exprs []*ExprWhitelist
|
|
}
|
|
|
|
type ExprWhitelist struct {
|
|
Filter *vm.Program
|
|
ExprDebugger *exprhelpers.ExprDebugger // used to debug expression by printing the content of each variable of the expression
|
|
}
|
|
|
|
func (n *Node) ContainsWLs() bool {
|
|
return n.ContainsIPLists() || n.ContainsExprLists()
|
|
}
|
|
|
|
func (n *Node) ContainsExprLists() bool {
|
|
return len(n.Whitelist.B_Exprs) > 0
|
|
}
|
|
|
|
func (n *Node) ContainsIPLists() bool {
|
|
return len(n.Whitelist.B_Ips) > 0 || len(n.Whitelist.B_Cidrs) > 0
|
|
}
|
|
|
|
func (n *Node) CheckIPsWL(srcs []net.IP) bool {
|
|
isWhitelisted := false
|
|
if !n.ContainsIPLists() {
|
|
return isWhitelisted
|
|
}
|
|
for _, src := range srcs {
|
|
if isWhitelisted {
|
|
break
|
|
}
|
|
for _, v := range n.Whitelist.B_Ips {
|
|
if v.Equal(src) {
|
|
n.Logger.Debugf("Event from [%s] is whitelisted by IP (%s), reason [%s]", src, v, n.Whitelist.Reason)
|
|
isWhitelisted = true
|
|
break
|
|
}
|
|
n.Logger.Tracef("whitelist: %s is not eq [%s]", src, v)
|
|
}
|
|
for _, v := range n.Whitelist.B_Cidrs {
|
|
if v.Contains(src) {
|
|
n.Logger.Debugf("Event from [%s] is whitelisted by CIDR (%s), reason [%s]", src, v, n.Whitelist.Reason)
|
|
isWhitelisted = true
|
|
break
|
|
}
|
|
n.Logger.Tracef("whitelist: %s not in [%s]", src, v)
|
|
}
|
|
}
|
|
return isWhitelisted
|
|
}
|
|
|
|
func (n *Node) CheckExprWL(cachedExprEnv map[string]interface{}) (bool, error) {
|
|
isWhitelisted := false
|
|
|
|
if !n.ContainsExprLists() {
|
|
return false, nil
|
|
}
|
|
/* run whitelist expression tests anyway */
|
|
for eidx, e := range n.Whitelist.B_Exprs {
|
|
//if we already know the event is whitelisted, skip the rest of the expressions
|
|
if isWhitelisted {
|
|
break
|
|
}
|
|
output, err := expr.Run(e.Filter, cachedExprEnv)
|
|
if err != nil {
|
|
n.Logger.Warningf("failed to run whitelist expr : %v", err)
|
|
n.Logger.Debug("Event leaving node : ko")
|
|
return isWhitelisted, err
|
|
}
|
|
switch out := output.(type) {
|
|
case bool:
|
|
if n.Debug {
|
|
e.ExprDebugger.Run(n.Logger, out, cachedExprEnv)
|
|
}
|
|
if out {
|
|
n.Logger.Debugf("Event is whitelisted by expr, reason [%s]", n.Whitelist.Reason)
|
|
isWhitelisted = true
|
|
}
|
|
default:
|
|
n.Logger.Errorf("unexpected type %t (%v) while running '%s'", output, output, n.Whitelist.Exprs[eidx])
|
|
}
|
|
}
|
|
return isWhitelisted, nil
|
|
}
|
|
|
|
func (n *Node) CompileWLs() (bool, error) {
|
|
for _, v := range n.Whitelist.Ips {
|
|
n.Whitelist.B_Ips = append(n.Whitelist.B_Ips, net.ParseIP(v))
|
|
n.Logger.Debugf("adding ip %s to whitelists", net.ParseIP(v))
|
|
}
|
|
|
|
for _, v := range n.Whitelist.Cidrs {
|
|
_, tnet, err := net.ParseCIDR(v)
|
|
if err != nil {
|
|
return false, fmt.Errorf("unable to parse cidr whitelist '%s' : %v", v, err)
|
|
}
|
|
n.Whitelist.B_Cidrs = append(n.Whitelist.B_Cidrs, tnet)
|
|
n.Logger.Debugf("adding cidr %s to whitelists", tnet)
|
|
}
|
|
|
|
for _, filter := range n.Whitelist.Exprs {
|
|
var err error
|
|
expression := &ExprWhitelist{}
|
|
expression.Filter, err = expr.Compile(filter, exprhelpers.GetExprOptions(map[string]interface{}{"evt": &types.Event{}})...)
|
|
if err != nil {
|
|
return false, fmt.Errorf("unable to compile whitelist expression '%s' : %v", filter, err)
|
|
}
|
|
expression.ExprDebugger, err = exprhelpers.NewDebugger(filter, exprhelpers.GetExprOptions(map[string]interface{}{"evt": &types.Event{}})...)
|
|
if err != nil {
|
|
n.Logger.Errorf("unable to build debug filter for '%s' : %s", filter, err)
|
|
}
|
|
|
|
n.Whitelist.B_Exprs = append(n.Whitelist.B_Exprs, expression)
|
|
n.Logger.Debugf("adding expression %s to whitelists", filter)
|
|
}
|
|
return n.ContainsWLs(), nil
|
|
}
|