Skip to content

Commit

Permalink
Add process_path_regex rule type
Browse files Browse the repository at this point in the history
  • Loading branch information
srk24 committed Sep 15, 2024
1 parent 7a48767 commit b578645
Show file tree
Hide file tree
Showing 15 changed files with 182 additions and 21 deletions.
9 changes: 9 additions & 0 deletions common/srs/binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const (
ruleItemWIFISSID
ruleItemWIFIBSSID
ruleItemAdGuardDomain
ruleItemProcessPathRegex
ruleItemFinal uint8 = 0xFF
)

Expand Down Expand Up @@ -207,6 +208,8 @@ func readDefaultRule(reader varbin.Reader, recover bool) (rule option.DefaultHea
rule.ProcessName, err = readRuleItemString(reader)
case ruleItemProcessPath:
rule.ProcessPath, err = readRuleItemString(reader)
case ruleItemProcessPathRegex:
rule.ProcessPathRegex, err = readRuleItemString(reader)
case ruleItemPackageName:
rule.PackageName, err = readRuleItemString(reader)
case ruleItemWIFISSID:
Expand Down Expand Up @@ -326,6 +329,12 @@ func writeDefaultRule(writer varbin.Writer, rule option.DefaultHeadlessRule, gen
return err
}
}
if len(rule.ProcessPathRegex) > 0 {
err = writeRuleItemString(writer, ruleItemProcessPathRegex, rule.ProcessPathRegex)
if err != nil {
return err
}
}
if len(rule.PackageName) > 0 {
err = writeRuleItemString(writer, ruleItemPackageName, rule.PackageName)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions docs/clients/android/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ SFA provides an unprivileged TUN implementation through Android VpnService.
|-----------------------|------------------|-----------------------------------|
| `process_name` | :material-close: | No permission |
| `process_path` | :material-close: | No permission |
| `process_path_regex` | :material-close: | No permission |
| `package_name` | :material-check: | / |
| `user` | :material-close: | Use `package_name` instead |
| `user_id` | :material-close: | Use `package_name` instead |
Expand Down
1 change: 1 addition & 0 deletions docs/clients/apple/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ SFI/SFM/SFT provides an unprivileged TUN implementation through NetworkExtension
|-----------------------|------------------|-----------------------|
| `process_name` | :material-close: | No permission |
| `process_path` | :material-close: | No permission |
| `process_path_regex` | :material-close: | No permission |
| `package_name` | :material-close: | / |
| `user` | :material-close: | No permission |
| `user_id` | :material-close: | No permission |
Expand Down
16 changes: 15 additions & 1 deletion docs/configuration/dns/rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ icon: material/new-box

:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
:material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source)
:material-plus: [rule_set_ip_cidr_accept_empty](#rule_set_ip_cidr_accept_empty)
:material-plus: [rule_set_ip_cidr_accept_empty](#rule_set_ip_cidr_accept_empty)
:material-plus: [process_path_regex](#process_path_regex)

!!! quote "Changes in sing-box 1.9.0"

Expand Down Expand Up @@ -103,6 +104,9 @@ icon: material/new-box
"process_path": [
"/usr/bin/curl"
],
"process_path_regex": [
"^/usr/bin/.+"
],
"package_name": [
"com.termux"
],
Expand Down Expand Up @@ -268,6 +272,16 @@ Match process name.

Match process path.

#### process_path_regex

!!! question "Since sing-box 1.10.0"

!!! quote ""

Only supported on Linux, Windows, and macOS.

Match process path using regular expression.

#### package_name

Match android package name.
Expand Down
16 changes: 15 additions & 1 deletion docs/configuration/dns/rule.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ icon: material/new-box

:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
:material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source)
:material-plus: [rule_set_ip_cidr_accept_empty](#rule_set_ip_cidr_accept_empty)
:material-plus: [rule_set_ip_cidr_accept_empty](#rule_set_ip_cidr_accept_empty)
:material-plus: [process_path_regex](#process_path_regex)

!!! quote "sing-box 1.9.0 中的更改"

Expand Down Expand Up @@ -103,6 +104,9 @@ icon: material/new-box
"process_path": [
"/usr/bin/curl"
],
"process_path_regex": [
"^/usr/bin/.+"
],
"package_name": [
"com.termux"
],
Expand Down Expand Up @@ -266,6 +270,16 @@ DNS 查询类型。值可以为整数或者类型名称字符串。

匹配进程路径。

#### process_path_regex

!!! question "自 sing-box 1.10.0 起"

!!! quote ""

仅支持 Linux、Windows 和 macOS.

使用正则表达式匹配进程路径。

#### package_name

匹配 Android 应用包名。
Expand Down
14 changes: 14 additions & 0 deletions docs/configuration/route/rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ icon: material/alert-decagram
:material-plus: [client](#client)
:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
:material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source)
:material-plus: [process_path_regex](#process_path_regex)

!!! quote "Changes in sing-box 1.8.0"

Expand Down Expand Up @@ -101,6 +102,9 @@ icon: material/alert-decagram
"process_path": [
"/usr/bin/curl"
],
"process_path_regex": [
"^/usr/bin/.+"
],
"package_name": [
"com.termux"
],
Expand Down Expand Up @@ -277,6 +281,16 @@ Match process name.

Match process path.

#### process_path_regex

!!! question "Since sing-box 1.10.0"

!!! quote ""

Only supported on Linux, Windows, and macOS.

Match process path using regular expression.

#### package_name

Match android package name.
Expand Down
16 changes: 15 additions & 1 deletion docs/configuration/route/rule.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ icon: material/alert-decagram

:material-plus: [client](#client)
:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
:material-plus: [rule_set_ip_cidr_match_source](#rule_set_ip_cidr_match_source)
:material-plus: [process_path_regex](#process_path_regex)


!!! quote "sing-box 1.8.0 中的更改"

Expand Down Expand Up @@ -99,6 +100,9 @@ icon: material/alert-decagram
"process_path": [
"/usr/bin/curl"
],
"process_path_regex": [
"^/usr/bin/.+"
],
"package_name": [
"com.termux"
],
Expand Down Expand Up @@ -275,6 +279,16 @@ icon: material/alert-decagram

匹配进程路径。

#### process_path_regex

!!! question "自 sing-box 1.10.0 起"

!!! quote ""

仅支持 Linux、Windows 和 macOS.

使用正则表达式匹配进程路径。

#### package_name

匹配 Android 应用包名。
Expand Down
13 changes: 13 additions & 0 deletions docs/configuration/rule-set/headless-rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
"process_path": [
"/usr/bin/curl"
],
"process_path_regex": [
"^/usr/bin/.+"
],
"package_name": [
"com.termux"
],
Expand Down Expand Up @@ -160,6 +163,16 @@ Match process name.

Match process path.

#### process_path_regex

!!! question "Since sing-box 1.10.0"

!!! quote ""

Only supported on Linux, Windows, and macOS.

Match process path using regular expression.

#### package_name

Match android package name.
Expand Down
1 change: 1 addition & 0 deletions option/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ type _DefaultRule struct {
PortRange Listable[string] `json:"port_range,omitempty"`
ProcessName Listable[string] `json:"process_name,omitempty"`
ProcessPath Listable[string] `json:"process_path,omitempty"`
ProcessPathRegex Listable[string] `json:"process_path_regex,omitempty"`
PackageName Listable[string] `json:"package_name,omitempty"`
User Listable[string] `json:"user,omitempty"`
UserID Listable[int32] `json:"user_id,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions option/rule_dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ type _DefaultDNSRule struct {
PortRange Listable[string] `json:"port_range,omitempty"`
ProcessName Listable[string] `json:"process_name,omitempty"`
ProcessPath Listable[string] `json:"process_path,omitempty"`
ProcessPathRegex Listable[string] `json:"process_path_regex,omitempty"`
PackageName Listable[string] `json:"package_name,omitempty"`
User Listable[string] `json:"user,omitempty"`
UserID Listable[int32] `json:"user_id,omitempty"`
Expand Down
37 changes: 19 additions & 18 deletions option/rule_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,24 +144,25 @@ func (r HeadlessRule) IsValid() bool {
}

type DefaultHeadlessRule struct {
QueryType Listable[DNSQueryType] `json:"query_type,omitempty"`
Network Listable[string] `json:"network,omitempty"`
Domain Listable[string] `json:"domain,omitempty"`
DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
DomainRegex Listable[string] `json:"domain_regex,omitempty"`
SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
IPCIDR Listable[string] `json:"ip_cidr,omitempty"`
SourcePort Listable[uint16] `json:"source_port,omitempty"`
SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
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"`
WIFISSID Listable[string] `json:"wifi_ssid,omitempty"`
WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"`
Invert bool `json:"invert,omitempty"`
QueryType Listable[DNSQueryType] `json:"query_type,omitempty"`
Network Listable[string] `json:"network,omitempty"`
Domain Listable[string] `json:"domain,omitempty"`
DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
DomainRegex Listable[string] `json:"domain_regex,omitempty"`
SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
IPCIDR Listable[string] `json:"ip_cidr,omitempty"`
SourcePort Listable[uint16] `json:"source_port,omitempty"`
SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
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"`
ProcessPathRegex Listable[string] `json:"process_path_regex,omitempty"`
PackageName Listable[string] `json:"package_name,omitempty"`
WIFISSID Listable[string] `json:"wifi_ssid,omitempty"`
WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"`
Invert bool `json:"invert,omitempty"`

DomainMatcher *domain.Matcher `json:"-"`
SourceIPSet *netipx.IPSet `json:"-"`
Expand Down
8 changes: 8 additions & 0 deletions route/rule_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,14 @@ 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.ProcessPathRegex) > 0 {
item, err := NewProcessPathRegexItem(options.ProcessPathRegex)
if err != nil {
return nil, E.Cause(err, "process_path_regex")
}
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)
Expand Down
8 changes: 8 additions & 0 deletions route/rule_dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,14 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options
rule.items = append(rule.items, item)
rule.allItems = append(rule.allItems, item)
}
if len(options.ProcessPathRegex) > 0 {
item, err := NewProcessPathRegexItem(options.ProcessPathRegex)
if err != nil {
return nil, E.Cause(err, "process_path_regex")
}
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)
Expand Down
8 changes: 8 additions & 0 deletions route/rule_headless.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ func NewDefaultHeadlessRule(router adapter.Router, options option.DefaultHeadles
rule.items = append(rule.items, item)
rule.allItems = append(rule.allItems, item)
}
if len(options.ProcessPathRegex) > 0 {
item, err := NewProcessPathRegexItem(options.ProcessPathRegex)
if err != nil {
return nil, E.Cause(err, "process_path_regex")
}
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)
Expand Down
54 changes: 54 additions & 0 deletions route/rule_item_process_path_regex.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package route

import (
"regexp"
"strings"

"github.com/sagernet/sing-box/adapter"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
)

var _ RuleItem = (*ProcessPathRegexItem)(nil)

type ProcessPathRegexItem struct {
matchers []*regexp.Regexp
description string
}

func NewProcessPathRegexItem(expressions []string) (*ProcessPathRegexItem, error) {
matchers := make([]*regexp.Regexp, 0, len(expressions))
for i, regex := range expressions {
matcher, err := regexp.Compile(regex)
if err != nil {
return nil, E.Cause(err, "parse expression ", i)
}
matchers = append(matchers, matcher)
}
description := "process_path_regex="
eLen := len(expressions)
if eLen == 1 {
description += expressions[0]
} else if eLen > 3 {
description += F.ToString("[", strings.Join(expressions[:3], " "), "]")
} else {
description += F.ToString("[", strings.Join(expressions, " "), "]")
}
return &ProcessPathRegexItem{matchers, description}, nil
}

func (r *ProcessPathRegexItem) Match(metadata *adapter.InboundContext) bool {
if metadata.ProcessInfo == nil || metadata.ProcessInfo.ProcessPath == "" {
return false
}
for _, matcher := range r.matchers {
if matcher.MatchString(metadata.ProcessInfo.ProcessPath) {
return true
}
}
return false
}

func (r *ProcessPathRegexItem) String() string {
return r.description
}

0 comments on commit b578645

Please sign in to comment.