diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index b39ee3a659..69fbb61799 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -48,7 +48,7 @@ type GroupBaseOption struct { func NewGroupBase(opt GroupBaseOption) *GroupBase { var excludeFilterReg *regexp2.Regexp if opt.excludeFilter != "" { - excludeFilterReg = regexp2.MustCompile(opt.excludeFilter, 0) + excludeFilterReg = regexp2.MustCompile(opt.excludeFilter, regexp2.None) } var excludeTypeArray []string if opt.excludeType != "" { @@ -58,7 +58,7 @@ func NewGroupBase(opt GroupBaseOption) *GroupBase { var filterRegs []*regexp2.Regexp if opt.filter != "" { for _, filter := range strings.Split(opt.filter, "`") { - filterReg := regexp2.MustCompile(filter, 0) + filterReg := regexp2.MustCompile(filter, regexp2.None) filterRegs = append(filterRegs, filterReg) } } @@ -126,7 +126,7 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy { for _, filterReg := range gb.filterRegs { for _, p := range proxies { name := p.Name() - if mat, _ := filterReg.FindStringMatch(name); mat != nil { + if mat, _ := filterReg.MatchString(name); mat { if _, ok := proxiesSet[name]; !ok { proxiesSet[name] = struct{}{} newProxies = append(newProxies, p) @@ -150,7 +150,7 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy { for _, filterReg := range gb.filterRegs { for _, p := range proxies { name := p.Name() - if mat, _ := filterReg.FindStringMatch(name); mat != nil { + if mat, _ := filterReg.MatchString(name); mat { if _, ok := proxiesSet[name]; !ok { proxiesSet[name] = struct{}{} newProxies = append(newProxies, p) @@ -191,7 +191,7 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy { var newProxies []C.Proxy for _, p := range proxies { name := p.Name() - if mat, _ := gb.excludeFilterReg.FindStringMatch(name); mat != nil { + if mat, _ := gb.excludeFilterReg.MatchString(name); mat { continue } newProxies = append(newProxies, p) diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index 941179e097..67dc104dfb 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -75,12 +75,12 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide if groupOption.Filter != "" { var filterRegs []*regexp2.Regexp for _, filter := range strings.Split(groupOption.Filter, "`") { - filterReg := regexp2.MustCompile(filter, 0) + filterReg := regexp2.MustCompile(filter, regexp2.None) filterRegs = append(filterRegs, filterReg) } for _, p := range AllProxies { for _, filterReg := range filterRegs { - if mat, _ := filterReg.FindStringMatch(p); mat != nil { + if mat, _ := filterReg.MatchString(p); mat { groupOption.Proxies = append(groupOption.Proxies, p) } } diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index bfbcf8d904..8b5e833851 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -181,14 +181,14 @@ func (hc *HealthCheck) execute(b *batch.Batch[bool], url, uid string, option *ex filters = append(filters, filter) } - filterReg = regexp2.MustCompile(strings.Join(filters, "|"), 0) + filterReg = regexp2.MustCompile(strings.Join(filters, "|"), regexp2.None) } } for _, proxy := range hc.proxies { // skip proxies that do not require health check if filterReg != nil { - if match, _ := filterReg.FindStringMatch(proxy.Name()); match == nil { + if match, _ := filterReg.MatchString(proxy.Name()); !match { continue } } diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index a40a50ec44..daef017c95 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -169,7 +169,7 @@ func stopProxyProvider(pd *ProxySetProvider) { } func NewProxySetProvider(name string, interval time.Duration, filter string, excludeFilter string, excludeType string, dialerProxy string, override OverrideSchema, vehicle types.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) { - excludeFilterReg, err := regexp2.Compile(excludeFilter, 0) + excludeFilterReg, err := regexp2.Compile(excludeFilter, regexp2.None) if err != nil { return nil, fmt.Errorf("invalid excludeFilter regex: %w", err) } @@ -180,7 +180,7 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, exc var filterRegs []*regexp2.Regexp for _, filter := range strings.Split(filter, "`") { - filterReg, err := regexp2.Compile(filter, 0) + filterReg, err := regexp2.Compile(filter, regexp2.None) if err != nil { return nil, fmt.Errorf("invalid filter regex: %w", err) } @@ -356,12 +356,12 @@ func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray continue } if len(excludeFilter) > 0 { - if mat, _ := excludeFilterReg.FindStringMatch(name); mat != nil { + if mat, _ := excludeFilterReg.MatchString(name); mat { continue } } if len(filter) > 0 { - if mat, _ := filterReg.FindStringMatch(name); mat == nil { + if mat, _ := filterReg.MatchString(name); !mat { continue } } diff --git a/constant/rule.go b/constant/rule.go index 8fdd75a6c0..161c200a60 100644 --- a/constant/rule.go +++ b/constant/rule.go @@ -22,8 +22,10 @@ const ( InUser InName InType - Process + ProcessName ProcessPath + ProcessNameRegex + ProcessPathRegex RuleSet Network Uid @@ -76,10 +78,14 @@ func (rt RuleType) String() string { return "InName" case InType: return "InType" - case Process: - return "Process" + case ProcessName: + return "ProcessName" case ProcessPath: return "ProcessPath" + case ProcessNameRegex: + return "ProcessNameRegex" + case ProcessPathRegex: + return "ProcessPathRegex" case MATCH: return "Match" case RuleSet: diff --git a/rules/common/domain_regex.go b/rules/common/domain_regex.go index 3d961542ad..d214a772c1 100644 --- a/rules/common/domain_regex.go +++ b/rules/common/domain_regex.go @@ -1,14 +1,14 @@ package common import ( - "regexp" - C "github.com/metacubex/mihomo/constant" + + "github.com/dlclark/regexp2" ) type DomainRegex struct { *Base - regex *regexp.Regexp + regex *regexp2.Regexp adapter string } @@ -18,7 +18,8 @@ func (dr *DomainRegex) RuleType() C.RuleType { func (dr *DomainRegex) Match(metadata *C.Metadata) (bool, string) { domain := metadata.RuleHost() - return dr.regex.MatchString(domain), dr.adapter + match, _ := dr.regex.MatchString(domain) + return match, dr.adapter } func (dr *DomainRegex) Adapter() string { @@ -30,7 +31,7 @@ func (dr *DomainRegex) Payload() string { } func NewDomainRegex(regex string, adapter string) (*DomainRegex, error) { - r, err := regexp.Compile(regex) + r, err := regexp2.Compile(regex, regexp2.IgnoreCase) if err != nil { return nil, err } diff --git a/rules/common/process.go b/rules/common/process.go index ce6435941a..8932e94660 100644 --- a/rules/common/process.go +++ b/rules/common/process.go @@ -4,6 +4,8 @@ import ( "strings" C "github.com/metacubex/mihomo/constant" + + "github.com/dlclark/regexp2" ) type Process struct { @@ -11,21 +13,36 @@ type Process struct { adapter string process string nameOnly bool + regexp *regexp2.Regexp } func (ps *Process) RuleType() C.RuleType { if ps.nameOnly { - return C.Process + 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) (bool, string) { 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 } @@ -41,11 +58,20 @@ func (ps *Process) ShouldFindProcess() bool { return true } -func NewProcess(process string, adapter string, nameOnly bool) (*Process, error) { +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) + if err != nil { + return nil, err + } + } return &Process{ Base: &Base{}, adapter: adapter, process: process, nameOnly: nameOnly, + regexp: r, }, nil } diff --git a/rules/parser.go b/rules/parser.go index 032a02e4b0..9b1f552007 100644 --- a/rules/parser.go +++ b/rules/parser.go @@ -50,9 +50,13 @@ 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) + parsed, parseErr = RC.NewProcess(payload, target, true, false) case "PROCESS-PATH": - parsed, parseErr = RC.NewProcess(payload, target, false) + parsed, parseErr = RC.NewProcess(payload, target, false, false) + case "PROCESS-NAME-REGEX": + parsed, parseErr = RC.NewProcess(payload, target, true, true) + case "PROCESS-PATH-REGEX": + parsed, parseErr = RC.NewProcess(payload, target, false, true) case "NETWORK": parsed, parseErr = RC.NewNetworkType(payload, target) case "UID":