Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

alternative solution #1

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions pkg/parser/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,11 @@ func (n *Node) process(p *types.Event, ctx UnixParserCtx, expressionEnv map[stri
if n.Name != "" {
NodesHits.With(prometheus.Labels{"source": p.Line.Src, "type": p.Line.Module, "name": n.Name}).Inc()
}

isWhitelisted, hasWhitelist, exprErr := n.Whitelist.Check(p.ParseIPSources(), cachedExprEnv)
exprErr := error(nil)
isWhitelisted := n.CheckIPsWL(p.ParseIPSources())
if !isWhitelisted {
isWhitelisted, exprErr = n.CheckExprWL(cachedExprEnv)
}
if exprErr != nil {
// Previous code returned nil if there was an error, so we keep this behavior
return false, nil //nolint:nilerr
Expand Down Expand Up @@ -340,9 +343,10 @@ func (n *Node) process(p *types.Event, ctx UnixParserCtx, expressionEnv map[stri
}

/*
This is to apply statics when the node *has* whitelists that successfully matched the node.
This is to apply statics when the node either was whitelisted, or is not a whitelist (it has no expr/ips wl)
It is overconvoluted and should be simplified
*/
if len(n.Statics) > 0 && (isWhitelisted || !hasWhitelist) {
if len(n.Statics) > 0 && (isWhitelisted || !n.ContainsWLs()) {
clog.Debugf("+ Processing %d statics", len(n.Statics))
// if all else is good in whitelist, process node's statics
err := n.ProcessStatics(n.Statics, p)
Expand Down Expand Up @@ -555,7 +559,7 @@ func (n *Node) compile(pctx *UnixParserCtx, ectx EnricherCtx) error {
}

/* compile whitelists if present */
whitelistValid, err := n.Whitelist.Compile(n)
whitelistValid, err := n.CompileWLs()
if err != nil {
return err
}
Expand Down
113 changes: 62 additions & 51 deletions pkg/parser/whitelist.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,91 +19,107 @@ type Whitelist struct {
B_Cidrs []*net.IPNet
Exprs []string `yaml:"expression,omitempty"`
B_Exprs []*ExprWhitelist
Node *Node `yaml:"-"` // Pointer to the node containing this whitelist
}

func (W Whitelist) ContainsIPLists() bool {
return len(W.B_Ips) > 0 || len(W.B_Cidrs) > 0
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 (W Whitelist) ContainsExprLists() bool {
return len(W.B_Exprs) > 0
func (n *Node) ContainsIPLists() bool {
return len(n.Whitelist.B_Ips) > 0 || len(n.Whitelist.B_Cidrs) > 0
}

func (W Whitelist) Check(srcs []net.IP, cachedExprEnv map[string]interface{}) (bool, bool, error) {
func (n *Node) CheckIPsWL(srcs []net.IP) bool {
isWhitelisted := false
hasWhitelist := false
var err error
var output interface{}
if W.ContainsIPLists() {
for _, src := range srcs {
if isWhitelisted {
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
}
for _, v := range W.B_Ips {
if v.Equal(src) {
W.Node.Logger.Debugf("Event from [%s] is whitelisted by IP (%s), reason [%s]", src, v, W.Reason)
isWhitelisted = true
break
}
W.Node.Logger.Tracef("whitelist: %s is not eq [%s]", src, v)
}
for _, v := range W.B_Cidrs {
if v.Contains(src) {
W.Node.Logger.Debugf("Event from [%s] is whitelisted by CIDR (%s), reason [%s]", src, v, W.Reason)
isWhitelisted = true
break
}
W.Node.Logger.Tracef("whitelist: %s not in [%s]", src, v)
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)
}
hasWhitelist = true
}
return isWhitelisted
}

func (n *Node) CheckExprWL(cachedExprEnv map[string]interface{}) (bool, error) {
err := error(nil)
output := interface{}(nil)

isWhitelisted := false

if !n.ContainsExprLists() {
return false, nil
}
/* run whitelist expression tests anyway */
for eidx, e := range W.B_Exprs {
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 {
W.Node.Logger.Warningf("failed to run whitelist expr : %v", err)
W.Node.Logger.Debug("Event leaving node : ko")
n.Logger.Warningf("failed to run whitelist expr : %v", err)
n.Logger.Debug("Event leaving node : ko")
break
}
switch out := output.(type) {
case bool:
if W.Node.Debug {
e.ExprDebugger.Run(W.Node.Logger, out, cachedExprEnv)
if n.Debug {
e.ExprDebugger.Run(n.Logger, out, cachedExprEnv)
}
if out {
W.Node.Logger.Debugf("Event is whitelisted by expr, reason [%s]", W.Reason)
n.Logger.Debugf("Event is whitelisted by expr, reason [%s]", n.Whitelist.Reason)
isWhitelisted = true
}
hasWhitelist = true
default:
W.Node.Logger.Errorf("unexpected type %t (%v) while running '%s'", output, output, W.Exprs[eidx])
n.Logger.Errorf("unexpected type %t (%v) while running '%s'", output, output, n.Whitelist.Exprs[eidx])
}
}
return isWhitelisted, hasWhitelist, err
return isWhitelisted, err
}

func (W *Whitelist) Compile(n *Node) (bool, error) {
for _, v := range W.Ips {
W.B_Ips = append(W.B_Ips, net.ParseIP(v))
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 W.Cidrs {
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)
}
W.B_Cidrs = append(W.B_Cidrs, tnet)
n.Whitelist.B_Cidrs = append(n.Whitelist.B_Cidrs, tnet)
n.Logger.Debugf("adding cidr %s to whitelists", tnet)
}

for _, filter := range W.Exprs {
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{}})...)
Expand All @@ -114,18 +130,13 @@ func (W *Whitelist) Compile(n *Node) (bool, error) {
if err != nil {
n.Logger.Errorf("unable to build debug filter for '%s' : %s", filter, err)
}
W.B_Exprs = append(W.B_Exprs, expression)

n.Whitelist.B_Exprs = append(n.Whitelist.B_Exprs, expression)
n.Logger.Debugf("adding expression %s to whitelists", filter)
}
valid := false
if W.ContainsIPLists() || W.ContainsExprLists() {
W.Node = n
if n.ContainsIPLists() || n.ContainsExprLists() {
valid = true
}
return valid, nil
}

type ExprWhitelist struct {
Filter *vm.Program
ExprDebugger *exprhelpers.ExprDebugger // used to debug expression by printing the content of each variable of the expression
}
12 changes: 9 additions & 3 deletions pkg/parser/whitelist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ func TestWhitelistCompile(t *testing.T) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
_, err := tt.whitelist.Compile(node)
node.Whitelist = tt.whitelist
_, err := node.CompileWLs()
if err == nil && tt.expected_err {
t.Fatalf("Whitelist expected to error %s", tt.name)
}
Expand Down Expand Up @@ -163,8 +164,13 @@ func TestWhitelistCheck(t *testing.T) {
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
tt.whitelist.Compile(node)
isWhitelisted, _, err := tt.whitelist.Check(tt.sources, map[string]interface{}{"evt": tt.event})
var err error
node.Whitelist = tt.whitelist
node.CompileWLs()
isWhitelisted := node.CheckIPsWL(tt.sources)
if !isWhitelisted {
isWhitelisted, err = node.CheckExprWL(map[string]interface{}{"evt": tt.event})
}
if err != nil {
t.Fatalf("failed to check whitelist: %s", err)
}
Expand Down