diff --git a/option/dns.go b/option/dns.go index aac75ea8..d8da0ff1 100644 --- a/option/dns.go +++ b/option/dns.go @@ -94,6 +94,7 @@ type DefaultDNSRule struct { Port Listable[uint16] `json:"port,omitempty"` PortRange Listable[string] `json:"port_range,omitempty"` ProcessName Listable[string] `json:"process_name,omitempty"` + ProcessPath Listable[string] `json:"process_path,omitempty"` PackageName Listable[string] `json:"package_name,omitempty"` User Listable[string] `json:"user,omitempty"` UserID Listable[int32] `json:"user_id,omitempty"` diff --git a/option/route.go b/option/route.go index 6f54b7df..86f31d23 100644 --- a/option/route.go +++ b/option/route.go @@ -96,6 +96,7 @@ type DefaultRule struct { Port Listable[uint16] `json:"port,omitempty"` PortRange Listable[string] `json:"port_range,omitempty"` ProcessName Listable[string] `json:"process_name,omitempty"` + ProcessPath Listable[string] `json:"process_path,omitempty"` PackageName Listable[string] `json:"package_name,omitempty"` User Listable[string] `json:"user,omitempty"` UserID Listable[int32] `json:"user_id,omitempty"` diff --git a/route/router.go b/route/router.go index 42c3fadf..a95ed1f1 100644 --- a/route/router.go +++ b/route/router.go @@ -789,11 +789,11 @@ func isGeositeDNSRule(rule option.DefaultDNSRule) bool { } func isProcessRule(rule option.DefaultRule) bool { - return len(rule.ProcessName) > 0 || len(rule.PackageName) > 0 || len(rule.User) > 0 || len(rule.UserID) > 0 + return len(rule.ProcessName) > 0 || len(rule.ProcessPath) > 0 || len(rule.PackageName) > 0 || len(rule.User) > 0 || len(rule.UserID) > 0 } func isProcessDNSRule(rule option.DefaultDNSRule) bool { - return len(rule.ProcessName) > 0 || len(rule.PackageName) > 0 || len(rule.User) > 0 || len(rule.UserID) > 0 + return len(rule.ProcessName) > 0 || len(rule.ProcessPath) > 0 || len(rule.PackageName) > 0 || len(rule.User) > 0 || len(rule.UserID) > 0 } func notPrivateNode(code string) bool { diff --git a/route/rule.go b/route/rule.go index 35d7d24f..12186e4b 100644 --- a/route/rule.go +++ b/route/rule.go @@ -172,6 +172,11 @@ func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options opt rule.items = append(rule.items, item) rule.allItems = append(rule.allItems, item) } + if len(options.ProcessPath) > 0 { + item := NewProcessPathItem(options.ProcessPath) + rule.items = append(rule.items, item) + rule.allItems = append(rule.allItems, item) + } if len(options.PackageName) > 0 { item := NewPackageNameItem(options.PackageName) rule.items = append(rule.items, item) diff --git a/route/rule_dns.go b/route/rule_dns.go index 053bf777..6364f548 100644 --- a/route/rule_dns.go +++ b/route/rule_dns.go @@ -155,6 +155,11 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options rule.items = append(rule.items, item) rule.allItems = append(rule.allItems, item) } + if len(options.ProcessPath) > 0 { + item := NewProcessPathItem(options.ProcessPath) + rule.items = append(rule.items, item) + rule.allItems = append(rule.allItems, item) + } if len(options.PackageName) > 0 { item := NewPackageNameItem(options.PackageName) rule.items = append(rule.items, item) diff --git a/route/rule_process.go b/route/rule_process_name.go similarity index 87% rename from route/rule_process.go rename to route/rule_process_name.go index d09d3eb4..b0a151a1 100644 --- a/route/rule_process.go +++ b/route/rule_process_name.go @@ -11,7 +11,7 @@ import ( var warnProcessNameOnNonSupportedPlatform = warning.New( func() bool { return !(C.IsLinux || C.IsWindows || C.IsDarwin) }, - "rule item `process_item` is only supported on Linux, Windows, and macOS", + "rule item `process_name` is only supported on Linux, Windows and macOS", ) var _ RuleItem = (*ProcessItem)(nil) @@ -37,7 +37,7 @@ func (r *ProcessItem) Match(metadata *adapter.InboundContext) bool { if metadata.ProcessInfo == nil || metadata.ProcessInfo.ProcessPath == "" { return false } - return r.processMap[strings.ToLower(filepath.Base(metadata.ProcessInfo.ProcessPath))] + return r.processMap[filepath.Base(metadata.ProcessInfo.ProcessPath)] } func (r *ProcessItem) String() string { diff --git a/route/rule_process_path.go b/route/rule_process_path.go new file mode 100644 index 00000000..4398f614 --- /dev/null +++ b/route/rule_process_path.go @@ -0,0 +1,51 @@ +package route + +import ( + "strings" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/warning" + C "github.com/sagernet/sing-box/constant" +) + +var warnProcessPathOnNonSupportedPlatform = warning.New( + func() bool { return !(C.IsLinux || C.IsWindows || C.IsDarwin) }, + "rule item `process_path` is only supported on Linux, Windows and macOS", +) + +var _ RuleItem = (*ProcessPathItem)(nil) + +type ProcessPathItem struct { + processes []string + processMap map[string]bool +} + +func NewProcessPathItem(processNameList []string) *ProcessPathItem { + warnProcessPathOnNonSupportedPlatform.Check() + rule := &ProcessPathItem{ + processes: processNameList, + processMap: make(map[string]bool), + } + for _, processName := range processNameList { + rule.processMap[processName] = true + } + return rule +} + +func (r *ProcessPathItem) Match(metadata *adapter.InboundContext) bool { + if metadata.ProcessInfo == nil || metadata.ProcessInfo.ProcessPath == "" { + return false + } + return r.processMap[metadata.ProcessInfo.ProcessPath] +} + +func (r *ProcessPathItem) String() string { + var description string + pLen := len(r.processes) + if pLen == 1 { + description = "process_path=" + r.processes[0] + } else { + description = "process_path=[" + strings.Join(r.processes, " ") + "]" + } + return description +}