chore: improve built-in funcs handling (#43)

This commit is contained in:
Toby 2024-02-04 11:17:19 -08:00 committed by GitHub
parent f8f0153664
commit 6871244809
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -46,7 +46,6 @@ type compiledExprRule struct {
Action Action Action Action
ModInstance modifier.Instance ModInstance modifier.Instance
Program *vm.Program Program *vm.Program
Analyzers map[string]struct{}
} }
var _ Ruleset = (*exprRuleset)(nil) var _ Ruleset = (*exprRuleset)(nil)
@ -100,55 +99,45 @@ func CompileExprRules(rules []ExprRule, ans []analyzer.Analyzer, mods []modifier
if !ok { if !ok {
return nil, fmt.Errorf("rule %q has invalid action %q", rule.Name, rule.Action) return nil, fmt.Errorf("rule %q has invalid action %q", rule.Name, rule.Action)
} }
visitor := &depVisitor{Analyzers: make(map[string]struct{})} visitor := &idVisitor{Identifiers: make(map[string]bool)}
geoip := expr.Function(
"geoip",
func(params ...any) (any, error) {
return geoMatcher.MatchGeoIp(params[0].(string), params[1].(string)), nil
},
new(func(string, string) bool),
)
geosite := expr.Function(
"geosite",
func(params ...any) (any, error) {
return geoMatcher.MatchGeoSite(params[0].(string), params[1].(string)), nil
},
new(func(string, string) bool),
)
program, err := expr.Compile(rule.Expr, program, err := expr.Compile(rule.Expr,
func(c *conf.Config) { func(c *conf.Config) {
c.Strict = false c.Strict = false
c.Expect = reflect.Bool c.Expect = reflect.Bool
c.Visitors = append(c.Visitors, visitor) c.Visitors = append(c.Visitors, visitor)
registerBuiltinFunctions(c.Functions, geoMatcher)
}, },
geoip,
geosite,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("rule %q has invalid expression: %w", rule.Name, err) return nil, fmt.Errorf("rule %q has invalid expression: %w", rule.Name, err)
} }
for name := range visitor.Analyzers { for name := range visitor.Identifiers {
a, ok := fullAnMap[name] if isBuiltInAnalyzer(name) {
if !ok && !isBuiltInAnalyzer(name) { continue
return nil, fmt.Errorf("rule %q uses unknown analyzer %q", rule.Name, name)
} }
depAnMap[name] = a // Check if it's one of the built-in functions, and if so,
// skip it as an analyzer & do initialization if necessary.
switch name {
case "geoip":
if err := geoMatcher.LoadGeoIP(); err != nil {
return nil, fmt.Errorf("rule %q failed to load geoip: %w", rule.Name, err)
} }
if visitor.UseGeoSite { case "geosite":
if err := geoMatcher.LoadGeoSite(); err != nil { if err := geoMatcher.LoadGeoSite(); err != nil {
return nil, fmt.Errorf("rule %q failed to load geosite: %w", rule.Name, err) return nil, fmt.Errorf("rule %q failed to load geosite: %w", rule.Name, err)
} }
default:
a, ok := fullAnMap[name]
if !ok {
return nil, fmt.Errorf("rule %q uses unknown analyzer %q", rule.Name, name)
} }
if visitor.UseGeoIp { depAnMap[name] = a
if err := geoMatcher.LoadGeoIP(); err != nil {
return nil, fmt.Errorf("rule %q failed to load geoip: %w", rule.Name, err)
} }
} }
cr := compiledExprRule{ cr := compiledExprRule{
Name: rule.Name, Name: rule.Name,
Action: action, Action: action,
Program: program, Program: program,
Analyzers: visitor.Analyzers,
} }
if action == ActionModify { if action == ActionModify {
mod, ok := fullModMap[rule.Modifier.Name] mod, ok := fullModMap[rule.Modifier.Name]
@ -175,6 +164,23 @@ func CompileExprRules(rules []ExprRule, ans []analyzer.Analyzer, mods []modifier
}, nil }, nil
} }
func registerBuiltinFunctions(funcMap map[string]*ast.Function, geoMatcher *geo.GeoMatcher) {
funcMap["geoip"] = &ast.Function{
Name: "geoip",
Func: func(params ...any) (any, error) {
return geoMatcher.MatchGeoIp(params[0].(string), params[1].(string)), nil
},
Types: []reflect.Type{reflect.TypeOf(geoMatcher.MatchGeoIp)},
}
funcMap["geosite"] = &ast.Function{
Name: "geosite",
Func: func(params ...any) (any, error) {
return geoMatcher.MatchGeoSite(params[0].(string), params[1].(string)), nil
},
Types: []reflect.Type{reflect.TypeOf(geoMatcher.MatchGeoSite)},
}
}
func streamInfoToExprEnv(info StreamInfo) map[string]interface{} { func streamInfoToExprEnv(info StreamInfo) map[string]interface{} {
m := map[string]interface{}{ m := map[string]interface{}{
"id": info.ID, "id": info.ID,
@ -241,22 +247,12 @@ func modifiersToMap(mods []modifier.Modifier) map[string]modifier.Modifier {
return modMap return modMap
} }
type depVisitor struct { type idVisitor struct {
Analyzers map[string]struct{} Identifiers map[string]bool
UseGeoSite bool
UseGeoIp bool
} }
func (v *depVisitor) Visit(node *ast.Node) { func (v *idVisitor) Visit(node *ast.Node) {
if idNode, ok := (*node).(*ast.IdentifierNode); ok { if idNode, ok := (*node).(*ast.IdentifierNode); ok {
switch idNode.Value { v.Identifiers[idNode.Value] = true
case "geosite":
v.UseGeoSite = true
case "geoip":
v.UseGeoIp = true
default:
v.Analyzers[idNode.Value] = struct{}{}
}
} }
} }