engine: more performance improvements

This commit is contained in:
2026-05-18 09:17:24 +05:30
parent 77dba0c4fa
commit 581041b1a7
12 changed files with 1005 additions and 103 deletions
+98
View File
@@ -1,6 +1,7 @@
package ruleset
import (
"net"
"reflect"
"strings"
"testing"
@@ -12,6 +13,13 @@ import (
"github.com/expr-lang/expr/parser"
)
type testAnalyzer struct {
name string
}
func (a testAnalyzer) Name() string { return a.name }
func (a testAnalyzer) Limit() int { return 0 }
func TestExtractGeoSiteConditions(t *testing.T) {
expression := `
(geosite(tls.req.sni, "openai") || geosite(quic.req.sni, "OpenAI")) &&
@@ -88,3 +96,93 @@ func TestIDPatcher_PatchesGeoSiteORChainToGeoSiteSet(t *testing.T) {
t.Fatalf("expected OR chain to be collapsed, got %q", got)
}
}
func TestCompileExprRulesPrunesUnusedAnalyzers(t *testing.T) {
rs, err := CompileExprRules([]ExprRule{
{Name: "network-only", Action: "allow", Expr: `proto == "tcp" && port.dst == 443`},
}, []analyzer.Analyzer{testAnalyzer{name: "tls"}, testAnalyzer{name: "quic"}}, nil, &BuiltinConfig{})
if err != nil {
t.Fatalf("CompileExprRules error: %v", err)
}
exprRS := rs.(*exprRuleset)
if len(exprRS.Ans) != 0 {
t.Fatalf("expected no analyzers for network-only rule, got %d", len(exprRS.Ans))
}
if exprRS.Rules[0].Native == nil {
t.Fatalf("expected network-only rule to compile to native matcher")
}
got := rs.Match(StreamInfo{Protocol: ProtocolTCP, DstPort: 443})
if got.Action != ActionAllow {
t.Fatalf("native match action=%v want=%v", got.Action, ActionAllow)
}
}
func TestCompileExprRulesKeepsReferencedAnalyzersOnly(t *testing.T) {
rs, err := CompileExprRules([]ExprRule{
{Name: "tls-only", Action: "allow", Expr: `tls != nil && tls.req != nil && tls.req.sni == "example.com"`},
}, []analyzer.Analyzer{testAnalyzer{name: "tls"}, testAnalyzer{name: "quic"}}, nil, &BuiltinConfig{})
if err != nil {
t.Fatalf("CompileExprRules error: %v", err)
}
exprRS := rs.(*exprRuleset)
if len(exprRS.Ans) != 1 || exprRS.Ans[0].Name() != "tls" {
t.Fatalf("expected only tls analyzer, got %#v", exprRS.Ans)
}
}
func TestNativeCIDRMatcher(t *testing.T) {
funcMap, geoMatcher := buildFunctionMapForTest()
n := compileNativeExpr(`cidr(ip.src, "192.168.1.0/24") && port.dst >= 80 && port.dst <= 443`, funcMap, geoMatcher)
if n == nil {
t.Fatal("expected native matcher")
}
if !n.Match(StreamInfo{SrcIP: net.ParseIP("192.168.1.10"), DstPort: 443}) {
t.Fatal("expected native CIDR matcher to match")
}
if n.Match(StreamInfo{SrcIP: net.ParseIP("10.0.0.1"), DstPort: 443}) {
t.Fatal("expected native CIDR matcher not to match")
}
}
func TestCanFinalizeAfterLogForRequestOnlyActionRules(t *testing.T) {
rs, err := CompileExprRules([]ExprRule{
{Name: "log-host", Log: true, Expr: `tls != nil && tls.req != nil && tls.req.sni != nil`},
{Name: "block-bad-host", Action: "block", Expr: `tls != nil && tls.req != nil && tls.req.sni == "bad.example"`},
}, []analyzer.Analyzer{testAnalyzer{name: "tls"}}, nil, &BuiltinConfig{})
if err != nil {
t.Fatalf("CompileExprRules error: %v", err)
}
info := StreamInfo{
Props: analyzer.CombinedPropMap{
"tls": analyzer.PropMap{"req": analyzer.PropMap{"sni": "good.example"}},
},
}
if !rs.(LogFinalizer).CanFinalizeAfterLog(info, []string{"tls"}) {
t.Fatal("expected request-only rules to allow log finalization once request props exist")
}
}
func TestCanFinalizeAfterLogWaitsForResponseActionRules(t *testing.T) {
rs, err := CompileExprRules([]ExprRule{
{Name: "log-host", Log: true, Expr: `tls != nil && tls.req != nil && tls.req.sni != nil`},
{Name: "block-response", Action: "block", Expr: `tls != nil && tls.resp != nil && tls.resp.cipher_suite == "bad"`},
}, []analyzer.Analyzer{testAnalyzer{name: "tls"}}, nil, &BuiltinConfig{})
if err != nil {
t.Fatalf("CompileExprRules error: %v", err)
}
info := StreamInfo{
Props: analyzer.CombinedPropMap{
"tls": analyzer.PropMap{"req": analyzer.PropMap{"sni": "good.example"}},
},
}
if rs.(LogFinalizer).CanFinalizeAfterLog(info, []string{"tls"}) {
t.Fatal("expected response-side rule to keep inspection open")
}
}
func buildFunctionMapForTest() (map[string]*Function, *geo.GeoMatcher) {
m, g := buildFunctionMap(&BuiltinConfig{}, nil)
return m, g
}