From ed9e380a57f72e6ebd3d59841cc8d0793b2a700e Mon Sep 17 00:00:00 2001 From: Toby Date: Fri, 23 Feb 2024 14:37:05 -0800 Subject: [PATCH] fix: variable support & update example in doc --- README.ja.md | 8 +++++++- README.md | 8 +++++++- README.zh.md | 8 +++++++- ruleset/expr.go | 10 +++++++--- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/README.ja.md b/README.ja.md index e7ef209..694b44e 100644 --- a/README.ja.md +++ b/README.ja.md @@ -92,6 +92,11 @@ workers: 式言語の構文については、[Expr 言語定義](https://expr-lang.org/docs/language-definition)を参照してください。 ```yaml +# ルールは、"action" または "log" の少なくとも一方が設定されていなければなりません。 +- name: log horny people + log: true + expr: let sni = string(tls?.req?.sni); sni contains "porn" || sni contains "hentai" + - name: block v2ex http action: block expr: string(http?.req?.headers?.host) endsWith "v2ex.com" @@ -104,8 +109,9 @@ workers: action: block expr: string(quic?.req?.sni) endsWith "v2ex.com" -- name: block shadowsocks +- name: block and log shadowsocks action: block + log: true expr: fet != nil && fet.yes - name: block trojan diff --git a/README.md b/README.md index 4ed68ba..1878713 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,11 @@ For syntax of the expression language, please refer to [Expr Language Definition](https://expr-lang.org/docs/language-definition). ```yaml +# A rule must have at least one of "action" or "log" field set. +- name: log horny people + log: true + expr: let sni = string(tls?.req?.sni); sni contains "porn" || sni contains "hentai" + - name: block v2ex http action: block expr: string(http?.req?.headers?.host) endsWith "v2ex.com" @@ -110,8 +115,9 @@ to [Expr Language Definition](https://expr-lang.org/docs/language-definition). action: block expr: string(quic?.req?.sni) endsWith "v2ex.com" -- name: block shadowsocks +- name: block and log shadowsocks action: block + log: true expr: fet != nil && fet.yes - name: block trojan diff --git a/README.zh.md b/README.zh.md index 273f7cb..d5d6de4 100644 --- a/README.zh.md +++ b/README.zh.md @@ -93,6 +93,11 @@ workers: 规则的语法请参考 [Expr Language Definition](https://expr-lang.org/docs/language-definition)。 ```yaml +# 每条规则必须至少包含 action 或 log 中的一个。 +- name: log horny people + log: true + expr: let sni = string(tls?.req?.sni); sni contains "porn" || sni contains "hentai" + - name: block v2ex http action: block expr: string(http?.req?.headers?.host) endsWith "v2ex.com" @@ -105,8 +110,9 @@ workers: action: block expr: string(quic?.req?.sni) endsWith "v2ex.com" -- name: block shadowsocks +- name: block and log shadowsocks action: block + log: true expr: fet != nil && fet.yes - name: block trojan diff --git a/ruleset/expr.go b/ruleset/expr.go index cd07d30..7de924c 100644 --- a/ruleset/expr.go +++ b/ruleset/expr.go @@ -117,7 +117,7 @@ func CompileExprRules(rules []ExprRule, ans []analyzer.Analyzer, mods []modifier } action = &a } - visitor := &idVisitor{Identifiers: make(map[string]bool)} + visitor := &idVisitor{Variables: make(map[string]bool), Identifiers: make(map[string]bool)} patcher := &idPatcher{} program, err := expr.Compile(rule.Expr, func(c *conf.Config) { @@ -134,7 +134,8 @@ func CompileExprRules(rules []ExprRule, ans []analyzer.Analyzer, mods []modifier return nil, fmt.Errorf("rule %q failed to patch expression: %w", rule.Name, patcher.Err) } for name := range visitor.Identifiers { - if isBuiltInAnalyzer(name) { + // Skip built-in analyzers & user-defined variables + if isBuiltInAnalyzer(name) || visitor.Variables[name] { continue } // Check if it's one of the built-in functions, and if so, @@ -283,11 +284,14 @@ func modifiersToMap(mods []modifier.Modifier) map[string]modifier.Modifier { // idVisitor is a visitor that collects all identifiers in an expression. // This is for determining which analyzers are used by the expression. type idVisitor struct { + Variables map[string]bool Identifiers map[string]bool } func (v *idVisitor) Visit(node *ast.Node) { - if idNode, ok := (*node).(*ast.IdentifierNode); ok { + if varNode, ok := (*node).(*ast.VariableDeclaratorNode); ok { + v.Variables[varNode.Name] = true + } else if idNode, ok := (*node).(*ast.IdentifierNode); ok { v.Identifiers[idNode.Value] = true } }