fix: variable support & update example in doc

This commit is contained in:
Toby 2024-02-23 14:37:05 -08:00
parent 7353a16358
commit ed9e380a57
4 changed files with 28 additions and 6 deletions

View File

@ -92,6 +92,11 @@ workers:
式言語の構文については、[Expr 言語定義](https://expr-lang.org/docs/language-definition)を参照してください。 式言語の構文については、[Expr 言語定義](https://expr-lang.org/docs/language-definition)を参照してください。
```yaml ```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 - name: block v2ex http
action: block action: block
expr: string(http?.req?.headers?.host) endsWith "v2ex.com" expr: string(http?.req?.headers?.host) endsWith "v2ex.com"
@ -104,8 +109,9 @@ workers:
action: block action: block
expr: string(quic?.req?.sni) endsWith "v2ex.com" expr: string(quic?.req?.sni) endsWith "v2ex.com"
- name: block shadowsocks - name: block and log shadowsocks
action: block action: block
log: true
expr: fet != nil && fet.yes expr: fet != nil && fet.yes
- name: block trojan - name: block trojan

View File

@ -98,6 +98,11 @@ For syntax of the expression language, please refer
to [Expr Language Definition](https://expr-lang.org/docs/language-definition). to [Expr Language Definition](https://expr-lang.org/docs/language-definition).
```yaml ```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 - name: block v2ex http
action: block action: block
expr: string(http?.req?.headers?.host) endsWith "v2ex.com" 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 action: block
expr: string(quic?.req?.sni) endsWith "v2ex.com" expr: string(quic?.req?.sni) endsWith "v2ex.com"
- name: block shadowsocks - name: block and log shadowsocks
action: block action: block
log: true
expr: fet != nil && fet.yes expr: fet != nil && fet.yes
- name: block trojan - name: block trojan

View File

@ -93,6 +93,11 @@ workers:
规则的语法请参考 [Expr Language Definition](https://expr-lang.org/docs/language-definition)。 规则的语法请参考 [Expr Language Definition](https://expr-lang.org/docs/language-definition)。
```yaml ```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 - name: block v2ex http
action: block action: block
expr: string(http?.req?.headers?.host) endsWith "v2ex.com" expr: string(http?.req?.headers?.host) endsWith "v2ex.com"
@ -105,8 +110,9 @@ workers:
action: block action: block
expr: string(quic?.req?.sni) endsWith "v2ex.com" expr: string(quic?.req?.sni) endsWith "v2ex.com"
- name: block shadowsocks - name: block and log shadowsocks
action: block action: block
log: true
expr: fet != nil && fet.yes expr: fet != nil && fet.yes
- name: block trojan - name: block trojan

View File

@ -117,7 +117,7 @@ func CompileExprRules(rules []ExprRule, ans []analyzer.Analyzer, mods []modifier
} }
action = &a action = &a
} }
visitor := &idVisitor{Identifiers: make(map[string]bool)} visitor := &idVisitor{Variables: make(map[string]bool), Identifiers: make(map[string]bool)}
patcher := &idPatcher{} patcher := &idPatcher{}
program, err := expr.Compile(rule.Expr, program, err := expr.Compile(rule.Expr,
func(c *conf.Config) { 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) return nil, fmt.Errorf("rule %q failed to patch expression: %w", rule.Name, patcher.Err)
} }
for name := range visitor.Identifiers { for name := range visitor.Identifiers {
if isBuiltInAnalyzer(name) { // Skip built-in analyzers & user-defined variables
if isBuiltInAnalyzer(name) || visitor.Variables[name] {
continue continue
} }
// Check if it's one of the built-in functions, and if so, // 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. // idVisitor is a visitor that collects all identifiers in an expression.
// This is for determining which analyzers are used by the expression. // This is for determining which analyzers are used by the expression.
type idVisitor struct { type idVisitor struct {
Variables map[string]bool
Identifiers map[string]bool Identifiers map[string]bool
} }
func (v *idVisitor) Visit(node *ast.Node) { 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 v.Identifiers[idNode.Value] = true
} }
} }