From 487de9b5482d838acc33b067045a0dc293e35d40 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 6 Jan 2026 08:52:06 +0800 Subject: [PATCH] feat: add `PROCESS-NAME-WILDCARD` and `PROCESS-PATH-WILDCARD` --- constant/rule.go | 6 +++ rules/common/process.go | 90 ++++++++++++++++++++--------------------- rules/parser.go | 12 ++++-- 3 files changed, 57 insertions(+), 51 deletions(-) diff --git a/constant/rule.go b/constant/rule.go index a5941e6b..c6d1d8d6 100644 --- a/constant/rule.go +++ b/constant/rule.go @@ -27,6 +27,8 @@ const ( ProcessPath ProcessNameRegex ProcessPathRegex + ProcessNameWildcard + ProcessPathWildcard RuleSet Network Uid @@ -89,6 +91,10 @@ func (rt RuleType) String() string { return "ProcessNameRegex" case ProcessPathRegex: return "ProcessPathRegex" + case ProcessNameWildcard: + return "ProcessNameWildcard" + case ProcessPathWildcard: + return "ProcessPathWildcard" case MATCH: return "Match" case RuleSet: diff --git a/rules/common/process.go b/rules/common/process.go index c7e69574..f10fc5c5 100644 --- a/rules/common/process.go +++ b/rules/common/process.go @@ -3,6 +3,7 @@ package common import ( "strings" + "github.com/metacubex/mihomo/component/wildcard" C "github.com/metacubex/mihomo/constant" "github.com/dlclark/regexp2" @@ -10,67 +11,62 @@ import ( type Process struct { *Base + pattern string adapter string - process string - nameOnly bool + ruleType C.RuleType regexp *regexp2.Regexp } -func (ps *Process) RuleType() C.RuleType { - if ps.nameOnly { - if ps.regexp != nil { - return C.ProcessNameRegex - } - return C.ProcessName - } - - if ps.regexp != nil { - return C.ProcessPathRegex - } - return C.ProcessPath -} - -func (ps *Process) Match(metadata *C.Metadata, helper C.RuleMatchHelper) (bool, string) { - if helper.FindProcess != nil { - helper.FindProcess() - } - if ps.nameOnly { - if ps.regexp != nil { - match, _ := ps.regexp.MatchString(metadata.Process) - return match, ps.adapter - } - return strings.EqualFold(metadata.Process, ps.process), ps.adapter - } - - if ps.regexp != nil { - match, _ := ps.regexp.MatchString(metadata.ProcessPath) - return match, ps.adapter - } - return strings.EqualFold(metadata.ProcessPath, ps.process), ps.adapter +func (ps *Process) Payload() string { + return ps.pattern } func (ps *Process) Adapter() string { return ps.adapter } -func (ps *Process) Payload() string { - return ps.process +func (ps *Process) RuleType() C.RuleType { + return ps.ruleType } -func NewProcess(process string, adapter string, nameOnly bool, regex bool) (*Process, error) { - var r *regexp2.Regexp - var err error - if regex { - r, err = regexp2.Compile(process, regexp2.IgnoreCase) +func (ps *Process) Match(metadata *C.Metadata, helper C.RuleMatchHelper) (bool, string) { + if helper.FindProcess != nil { + helper.FindProcess() + } + var target string + switch ps.ruleType { + case C.ProcessName, C.ProcessNameRegex, C.ProcessNameWildcard: + target = metadata.Process + default: + target = metadata.ProcessPath + } + + switch ps.ruleType { + case C.ProcessNameRegex, C.ProcessPathRegex: + match, _ := ps.regexp.MatchString(target) + return match, ps.adapter + case C.ProcessNameWildcard, C.ProcessPathWildcard: + return wildcard.Match(strings.ToLower(ps.pattern), strings.ToLower(target)), ps.adapter + default: + return strings.EqualFold(target, ps.pattern), ps.adapter + } +} + +func NewProcess(pattern string, adapter string, ruleType C.RuleType) (*Process, error) { + ps := &Process{ + Base: &Base{}, + pattern: pattern, + adapter: adapter, + ruleType: ruleType, + } + switch ps.ruleType { + case C.ProcessNameRegex, C.ProcessPathRegex: + r, err := regexp2.Compile(pattern, regexp2.IgnoreCase) if err != nil { return nil, err } + ps.regexp = r + default: } - return &Process{ - Base: &Base{}, - adapter: adapter, - process: process, - nameOnly: nameOnly, - regexp: r, - }, nil + return ps, nil } diff --git a/rules/parser.go b/rules/parser.go index 6d8b3b8e..b2bf9642 100644 --- a/rules/parser.go +++ b/rules/parser.go @@ -56,13 +56,17 @@ func ParseRule(tp, payload, target string, params []string, subRules map[string] case "DSCP": parsed, parseErr = RC.NewDSCP(payload, target) case "PROCESS-NAME": - parsed, parseErr = RC.NewProcess(payload, target, true, false) + parsed, parseErr = RC.NewProcess(payload, target, C.ProcessName) case "PROCESS-PATH": - parsed, parseErr = RC.NewProcess(payload, target, false, false) + parsed, parseErr = RC.NewProcess(payload, target, C.ProcessPath) case "PROCESS-NAME-REGEX": - parsed, parseErr = RC.NewProcess(payload, target, true, true) + parsed, parseErr = RC.NewProcess(payload, target, C.ProcessNameRegex) case "PROCESS-PATH-REGEX": - parsed, parseErr = RC.NewProcess(payload, target, false, true) + parsed, parseErr = RC.NewProcess(payload, target, C.ProcessPathRegex) + case "PROCESS-NAME-WILDCARD": + parsed, parseErr = RC.NewProcess(payload, target, C.ProcessNameWildcard) + case "PROCESS-PATH-WILDCARD": + parsed, parseErr = RC.NewProcess(payload, target, C.ProcessPathWildcard) case "NETWORK": parsed, parseErr = RC.NewNetworkType(payload, target) case "UID":