mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-25 10:01:30 +00:00
Add network_[type/is_expensive/is_constrained]
rule items
This commit is contained in:
parent
acb0f32329
commit
04abbe8210
|
@ -1,6 +1,7 @@
|
||||||
package adguard
|
package adguard
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -26,7 +27,7 @@ example.arpa
|
||||||
`))
|
`))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, rules, 1)
|
require.Len(t, rules, 1)
|
||||||
rule, err := rule.NewHeadlessRule(nil, rules[0])
|
rule, err := rule.NewHeadlessRule(context.Background(), rules[0])
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
matchDomain := []string{
|
matchDomain := []string{
|
||||||
"example.org",
|
"example.org",
|
||||||
|
@ -85,7 +86,7 @@ func TestHosts(t *testing.T) {
|
||||||
`))
|
`))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, rules, 1)
|
require.Len(t, rules, 1)
|
||||||
rule, err := rule.NewHeadlessRule(nil, rules[0])
|
rule, err := rule.NewHeadlessRule(context.Background(), rules[0])
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
matchDomain := []string{
|
matchDomain := []string{
|
||||||
"google.com",
|
"google.com",
|
||||||
|
@ -115,7 +116,7 @@ www.example.org
|
||||||
`))
|
`))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, rules, 1)
|
require.Len(t, rules, 1)
|
||||||
rule, err := rule.NewHeadlessRule(nil, rules[0])
|
rule, err := rule.NewHeadlessRule(context.Background(), rules[0])
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
matchDomain := []string{
|
matchDomain := []string{
|
||||||
"example.com",
|
"example.com",
|
||||||
|
|
|
@ -38,6 +38,9 @@ const (
|
||||||
ruleItemWIFIBSSID
|
ruleItemWIFIBSSID
|
||||||
ruleItemAdGuardDomain
|
ruleItemAdGuardDomain
|
||||||
ruleItemProcessPathRegex
|
ruleItemProcessPathRegex
|
||||||
|
ruleItemNetworkType
|
||||||
|
ruleItemNetworkIsExpensive
|
||||||
|
ruleItemNetworkIsConstrained
|
||||||
ruleItemFinal uint8 = 0xFF
|
ruleItemFinal uint8 = 0xFF
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -222,6 +225,12 @@ func readDefaultRule(reader varbin.Reader, recover bool) (rule option.DefaultHea
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
rule.AdGuardDomainMatcher = matcher
|
rule.AdGuardDomainMatcher = matcher
|
||||||
|
case ruleItemNetworkType:
|
||||||
|
rule.NetworkType, err = readRuleItemString(reader)
|
||||||
|
case ruleItemNetworkIsExpensive:
|
||||||
|
rule.NetworkIsExpensive = true
|
||||||
|
case ruleItemNetworkIsConstrained:
|
||||||
|
rule.NetworkIsConstrained = true
|
||||||
case ruleItemFinal:
|
case ruleItemFinal:
|
||||||
err = binary.Read(reader, binary.BigEndian, &rule.Invert)
|
err = binary.Read(reader, binary.BigEndian, &rule.Invert)
|
||||||
return
|
return
|
||||||
|
@ -336,6 +345,27 @@ func writeDefaultRule(writer varbin.Writer, rule option.DefaultHeadlessRule, gen
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(rule.NetworkType) > 0 {
|
||||||
|
if generateVersion < C.RuleSetVersion3 {
|
||||||
|
return E.New("network_type rule item is only supported in version 3 or later")
|
||||||
|
}
|
||||||
|
err = writeRuleItemString(writer, ruleItemNetworkType, rule.NetworkType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if rule.NetworkIsExpensive {
|
||||||
|
err = binary.Write(writer, binary.BigEndian, ruleItemNetworkIsExpensive)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if rule.NetworkIsConstrained {
|
||||||
|
err = binary.Write(writer, binary.BigEndian, ruleItemNetworkIsConstrained)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
if len(rule.WIFISSID) > 0 {
|
if len(rule.WIFISSID) > 0 {
|
||||||
err = writeRuleItemString(writer, ruleItemWIFISSID, rule.WIFISSID)
|
err = writeRuleItemString(writer, ruleItemWIFISSID, rule.WIFISSID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -21,7 +21,8 @@ const (
|
||||||
const (
|
const (
|
||||||
RuleSetVersion1 = 1 + iota
|
RuleSetVersion1 = 1 + iota
|
||||||
RuleSetVersion2
|
RuleSetVersion2
|
||||||
RuleSetVersionCurrent = RuleSetVersion2
|
RuleSetVersion3
|
||||||
|
RuleSetVersionCurrent = RuleSetVersion3
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -9,6 +9,9 @@ icon: material/new-box
|
||||||
:material-alert: [disable_cache](#disable_cache)
|
:material-alert: [disable_cache](#disable_cache)
|
||||||
:material-alert: [rewrite_ttl](#rewrite_ttl)
|
:material-alert: [rewrite_ttl](#rewrite_ttl)
|
||||||
:material-alert: [client_subnet](#client_subnet)
|
:material-alert: [client_subnet](#client_subnet)
|
||||||
|
:material-plus: [network_type](#network_type)
|
||||||
|
:material-plus: [network_is_expensive](#network_is_expensive)
|
||||||
|
:material-plus: [network_is_constrained](#network_is_constrained)
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.10.0"
|
!!! quote "Changes in sing-box 1.10.0"
|
||||||
|
|
||||||
|
@ -125,6 +128,11 @@ icon: material/new-box
|
||||||
1000
|
1000
|
||||||
],
|
],
|
||||||
"clash_mode": "direct",
|
"clash_mode": "direct",
|
||||||
|
"network_type": [
|
||||||
|
"wifi"
|
||||||
|
],
|
||||||
|
"network_is_expensive": false,
|
||||||
|
"network_is_constrained": false,
|
||||||
"wifi_ssid": [
|
"wifi_ssid": [
|
||||||
"My WIFI"
|
"My WIFI"
|
||||||
],
|
],
|
||||||
|
@ -310,6 +318,39 @@ Match user id.
|
||||||
|
|
||||||
Match Clash mode.
|
Match Clash mode.
|
||||||
|
|
||||||
|
#### network_type
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.11.0"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
Only supported in graphical clients on Android and Apple platforms.
|
||||||
|
|
||||||
|
Match network type.
|
||||||
|
|
||||||
|
Available values: `wifi`, `cellular`, `ethernet` and `other`.
|
||||||
|
|
||||||
|
#### network_is_expensive
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.11.0"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
Only supported in graphical clients on Android and Apple platforms.
|
||||||
|
|
||||||
|
Match if network is considered Metered (on Android) or considered expensive,
|
||||||
|
such as Cellular or a Personal Hotspot (on Apple platforms).
|
||||||
|
|
||||||
|
#### network_is_constrained
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.11.0"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
Only supported in graphical clients on Apple platforms.
|
||||||
|
|
||||||
|
Match if network is in Low Data Mode.
|
||||||
|
|
||||||
#### wifi_ssid
|
#### wifi_ssid
|
||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
|
|
@ -2,6 +2,17 @@
|
||||||
icon: material/new-box
|
icon: material/new-box
|
||||||
---
|
---
|
||||||
|
|
||||||
|
!!! quote "sing-box 1.11.0 中的更改"
|
||||||
|
|
||||||
|
:material-plus: [action](#action)
|
||||||
|
:material-alert: [server](#server)
|
||||||
|
:material-alert: [disable_cache](#disable_cache)
|
||||||
|
:material-alert: [rewrite_ttl](#rewrite_ttl)
|
||||||
|
:material-alert: [client_subnet](#client_subnet)
|
||||||
|
:material-plus: [network_type](#network_type)
|
||||||
|
:material-plus: [network_is_expensive](#network_is_expensive)
|
||||||
|
:material-plus: [network_is_constrained](#network_is_constrained)
|
||||||
|
|
||||||
!!! quote "sing-box 1.10.0 中的更改"
|
!!! quote "sing-box 1.10.0 中的更改"
|
||||||
|
|
||||||
:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
||||||
|
@ -117,6 +128,11 @@ icon: material/new-box
|
||||||
1000
|
1000
|
||||||
],
|
],
|
||||||
"clash_mode": "direct",
|
"clash_mode": "direct",
|
||||||
|
"network_type": [
|
||||||
|
"wifi"
|
||||||
|
],
|
||||||
|
"network_is_expensive": false,
|
||||||
|
"network_is_constrained": false,
|
||||||
"wifi_ssid": [
|
"wifi_ssid": [
|
||||||
"My WIFI"
|
"My WIFI"
|
||||||
],
|
],
|
||||||
|
@ -135,17 +151,15 @@ icon: material/new-box
|
||||||
"outbound": [
|
"outbound": [
|
||||||
"direct"
|
"direct"
|
||||||
],
|
],
|
||||||
"server": "local",
|
"action": "route",
|
||||||
"disable_cache": false,
|
"server": "local"
|
||||||
"client_subnet": "127.0.0.1/24"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "logical",
|
"type": "logical",
|
||||||
"mode": "and",
|
"mode": "and",
|
||||||
"rules": [],
|
"rules": [],
|
||||||
"server": "local",
|
"action": "route",
|
||||||
"disable_cache": false,
|
"server": "local"
|
||||||
"client_subnet": "127.0.0.1/24"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -304,6 +318,39 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||||
|
|
||||||
匹配 Clash 模式。
|
匹配 Clash 模式。
|
||||||
|
|
||||||
|
#### network_type
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.11.0 起"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
|
匹配网络类型。
|
||||||
|
|
||||||
|
Available values: `wifi`, `cellular`, `ethernet` and `other`.
|
||||||
|
|
||||||
|
#### network_is_expensive
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.11.0 起"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
|
匹配如果网络被视为计费 (在 Android) 或被视为昂贵,
|
||||||
|
像蜂窝网络或个人热点 (在 Apple 平台)。
|
||||||
|
|
||||||
|
#### network_is_constrained
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.11.0 起"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅在 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
|
匹配如果网络在低数据模式下。
|
||||||
|
|
||||||
#### wifi_ssid
|
#### wifi_ssid
|
||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
@ -352,29 +399,35 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||||
|
|
||||||
`any` 可作为值用于匹配任意出站。
|
`any` 可作为值用于匹配任意出站。
|
||||||
|
|
||||||
#### server
|
#### action
|
||||||
|
|
||||||
==必填==
|
==必填==
|
||||||
|
|
||||||
目标 DNS 服务器的标签。
|
参阅 [规则动作](../rule_action/)。
|
||||||
|
|
||||||
|
#### server
|
||||||
|
|
||||||
|
!!! failure "已在 sing-box 1.11.0 废弃"
|
||||||
|
|
||||||
|
已移动到 [DNS 规则动作](../rule_action#route).
|
||||||
|
|
||||||
#### disable_cache
|
#### disable_cache
|
||||||
|
|
||||||
在此查询中禁用缓存。
|
!!! failure "已在 sing-box 1.11.0 废弃"
|
||||||
|
|
||||||
|
已移动到 [DNS 规则动作](../rule_action#route).
|
||||||
|
|
||||||
#### rewrite_ttl
|
#### rewrite_ttl
|
||||||
|
|
||||||
重写 DNS 回应中的 TTL。
|
!!! failure "已在 sing-box 1.11.0 废弃"
|
||||||
|
|
||||||
|
已移动到 [DNS 规则动作](../rule_action#route).
|
||||||
|
|
||||||
#### client_subnet
|
#### client_subnet
|
||||||
|
|
||||||
!!! question "自 sing-box 1.9.0 起"
|
!!! failure "已在 sing-box 1.11.0 废弃"
|
||||||
|
|
||||||
默认情况下,将带有指定 IP 前缀的 `edns0-subnet` OPT 附加记录附加到每个查询。
|
已移动到 [DNS 规则动作](../rule_action#route).
|
||||||
|
|
||||||
如果值是 IP 地址而不是前缀,则会自动附加 `/32` 或 `/128`。
|
|
||||||
|
|
||||||
将覆盖 `dns.client_subnet` 与 `servers.[].client_subnet`。
|
|
||||||
|
|
||||||
### 地址筛选字段
|
### 地址筛选字段
|
||||||
|
|
||||||
|
@ -420,8 +473,12 @@ DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||||
|
|
||||||
#### mode
|
#### mode
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
`and` 或 `or`
|
`and` 或 `or`
|
||||||
|
|
||||||
#### rules
|
#### rules
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
包括的规则。
|
包括的规则。
|
|
@ -6,6 +6,9 @@ icon: material/new-box
|
||||||
|
|
||||||
:material-plus: [action](#action)
|
:material-plus: [action](#action)
|
||||||
:material-alert: [outbound](#outbound)
|
:material-alert: [outbound](#outbound)
|
||||||
|
:material-plus: [network_type](#network_type)
|
||||||
|
:material-plus: [network_is_expensive](#network_is_expensive)
|
||||||
|
:material-plus: [network_is_constrained](#network_is_constrained)
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.10.0"
|
!!! quote "Changes in sing-box 1.10.0"
|
||||||
|
|
||||||
|
@ -120,6 +123,11 @@ icon: material/new-box
|
||||||
1000
|
1000
|
||||||
],
|
],
|
||||||
"clash_mode": "direct",
|
"clash_mode": "direct",
|
||||||
|
"network_type": [
|
||||||
|
"wifi"
|
||||||
|
],
|
||||||
|
"network_is_expensive": false,
|
||||||
|
"network_is_constrained": false,
|
||||||
"wifi_ssid": [
|
"wifi_ssid": [
|
||||||
"My WIFI"
|
"My WIFI"
|
||||||
],
|
],
|
||||||
|
@ -322,6 +330,39 @@ Match user id.
|
||||||
|
|
||||||
Match Clash mode.
|
Match Clash mode.
|
||||||
|
|
||||||
|
#### network_type
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.11.0"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
Only supported in graphical clients on Android and Apple platforms.
|
||||||
|
|
||||||
|
Match network type.
|
||||||
|
|
||||||
|
Available values: `wifi`, `cellular`, `ethernet` and `other`.
|
||||||
|
|
||||||
|
#### network_is_expensive
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.11.0"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
Only supported in graphical clients on Android and Apple platforms.
|
||||||
|
|
||||||
|
Match if network is considered Metered (on Android) or considered expensive,
|
||||||
|
such as Cellular or a Personal Hotspot (on Apple platforms).
|
||||||
|
|
||||||
|
#### network_is_constrained
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.11.0"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
Only supported in graphical clients on Apple platforms.
|
||||||
|
|
||||||
|
Match if network is in Low Data Mode.
|
||||||
|
|
||||||
#### wifi_ssid
|
#### wifi_ssid
|
||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
|
|
@ -6,6 +6,9 @@ icon: material/new-box
|
||||||
|
|
||||||
:material-plus: [action](#action)
|
:material-plus: [action](#action)
|
||||||
:material-alert: [outbound](#outbound)
|
:material-alert: [outbound](#outbound)
|
||||||
|
:material-plus: [network_type](#network_type)
|
||||||
|
:material-plus: [network_is_expensive](#network_is_expensive)
|
||||||
|
:material-plus: [network_is_constrained](#network_is_constrained)
|
||||||
|
|
||||||
!!! quote "sing-box 1.10.0 中的更改"
|
!!! quote "sing-box 1.10.0 中的更改"
|
||||||
|
|
||||||
|
@ -13,7 +16,6 @@ icon: material/new-box
|
||||||
:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
:material-delete-clock: [rule_set_ipcidr_match_source](#rule_set_ipcidr_match_source)
|
||||||
:material-plus: [process_path_regex](#process_path_regex)
|
:material-plus: [process_path_regex](#process_path_regex)
|
||||||
|
|
||||||
|
|
||||||
!!! quote "sing-box 1.8.0 中的更改"
|
!!! quote "sing-box 1.8.0 中的更改"
|
||||||
|
|
||||||
:material-plus: [rule_set](#rule_set)
|
:material-plus: [rule_set](#rule_set)
|
||||||
|
@ -118,6 +120,11 @@ icon: material/new-box
|
||||||
1000
|
1000
|
||||||
],
|
],
|
||||||
"clash_mode": "direct",
|
"clash_mode": "direct",
|
||||||
|
"network_type": [
|
||||||
|
"wifi"
|
||||||
|
],
|
||||||
|
"network_is_expensive": false,
|
||||||
|
"network_is_constrained": false,
|
||||||
"wifi_ssid": [
|
"wifi_ssid": [
|
||||||
"My WIFI"
|
"My WIFI"
|
||||||
],
|
],
|
||||||
|
@ -153,7 +160,7 @@ icon: material/new-box
|
||||||
|
|
||||||
当内容只有一项时,可以忽略 JSON 数组 [] 标签。
|
当内容只有一项时,可以忽略 JSON 数组 [] 标签。
|
||||||
|
|
||||||
### Default Fields
|
### 默认字段
|
||||||
|
|
||||||
!!! note ""
|
!!! note ""
|
||||||
|
|
||||||
|
@ -320,6 +327,39 @@ icon: material/new-box
|
||||||
|
|
||||||
匹配 Clash 模式。
|
匹配 Clash 模式。
|
||||||
|
|
||||||
|
#### network_type
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.11.0 起"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
|
匹配网络类型。
|
||||||
|
|
||||||
|
Available values: `wifi`, `cellular`, `ethernet` and `other`.
|
||||||
|
|
||||||
|
#### network_is_expensive
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.11.0 起"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
|
匹配如果网络被视为计费 (在 Android) 或被视为昂贵,
|
||||||
|
像蜂窝网络或个人热点 (在 Apple 平台)。
|
||||||
|
|
||||||
|
#### network_is_constrained
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.11.0 起"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅在 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
|
匹配如果网络在低数据模式下。
|
||||||
|
|
||||||
#### wifi_ssid
|
#### wifi_ssid
|
||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
@ -366,13 +406,13 @@ icon: material/new-box
|
||||||
|
|
||||||
==必填==
|
==必填==
|
||||||
|
|
||||||
参阅 [规则行动](../rule_action/)。
|
参阅 [规则动作](../rule_action/)。
|
||||||
|
|
||||||
#### outbound
|
#### outbound
|
||||||
|
|
||||||
!!! failure "已在 sing-box 1.11.0 废弃"
|
!!! failure "已在 sing-box 1.11.0 废弃"
|
||||||
|
|
||||||
已移动到 [规则行动](../rule_action#route).
|
已移动到 [规则动作](../rule_action#route).
|
||||||
|
|
||||||
### 逻辑字段
|
### 逻辑字段
|
||||||
|
|
||||||
|
|
70
docs/configuration/rule-set/adguard.zh.md
Normal file
70
docs/configuration/rule-set/adguard.zh.md
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
---
|
||||||
|
icon: material/new-box
|
||||||
|
---
|
||||||
|
|
||||||
|
# AdGuard DNS Filter
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.10.0 起"
|
||||||
|
|
||||||
|
sing-box 支持其他项目的一些规则集格式,这些格式无法完全转换为 sing-box,
|
||||||
|
目前只有 AdGuard DNS Filter。
|
||||||
|
|
||||||
|
这些格式不直接作为源格式支持,
|
||||||
|
而是需要将它们转换为二进制规则集。
|
||||||
|
|
||||||
|
## 转换
|
||||||
|
|
||||||
|
使用 `sing-box rule-set convert --type adguard [--output <file-name>.srs] <file-name>.txt` 以转换为二进制规则集。
|
||||||
|
|
||||||
|
## 性能
|
||||||
|
|
||||||
|
AdGuard 将所有规则保存在内存中并按顺序匹配,
|
||||||
|
而 sing-box 选择高性能和较小的内存使用量。
|
||||||
|
作为权衡,您无法知道匹配了哪个规则项。
|
||||||
|
|
||||||
|
## 兼容性
|
||||||
|
|
||||||
|
[AdGuardSDNSFilter](https://github.com/AdguardTeam/AdGuardSDNSFilter)
|
||||||
|
中的几乎所有规则以及 [adguard-filter-list](https://github.com/ppfeufer/adguard-filter-list)
|
||||||
|
中列出的规则集中的规则均受支持。
|
||||||
|
|
||||||
|
## 支持的格式
|
||||||
|
|
||||||
|
### AdGuard Filter
|
||||||
|
|
||||||
|
#### 基本规则语法
|
||||||
|
|
||||||
|
| 语法 | 支持 |
|
||||||
|
|--------|------------------|
|
||||||
|
| `@@` | :material-check: |
|
||||||
|
| `\|\|` | :material-check: |
|
||||||
|
| `\|` | :material-check: |
|
||||||
|
| `^` | :material-check: |
|
||||||
|
| `*` | :material-check: |
|
||||||
|
|
||||||
|
#### 主机语法
|
||||||
|
|
||||||
|
| 语法 | 示例 | 支持 |
|
||||||
|
|-------------|--------------------------|--------------------------|
|
||||||
|
| Scheme | `https://` | :material-alert: Ignored |
|
||||||
|
| Domain Host | `example.org` | :material-check: |
|
||||||
|
| IP Host | `1.1.1.1`, `10.0.0.` | :material-close: |
|
||||||
|
| Regexp | `/regexp/` | :material-check: |
|
||||||
|
| Port | `example.org:80` | :material-close: |
|
||||||
|
| Path | `example.org/path/ad.js` | :material-close: |
|
||||||
|
|
||||||
|
#### 描述符语法
|
||||||
|
|
||||||
|
| 描述符 | 支持 |
|
||||||
|
|-----------------------|--------------------------|
|
||||||
|
| `$important` | :material-check: |
|
||||||
|
| `$dnsrewrite=0.0.0.0` | :material-alert: Ignored |
|
||||||
|
| 任何其他描述符 | :material-close: |
|
||||||
|
|
||||||
|
### Hosts
|
||||||
|
|
||||||
|
只有 IP 地址为 `0.0.0.0` 的条目将被接受。
|
||||||
|
|
||||||
|
### 简易
|
||||||
|
|
||||||
|
当所有行都是有效域时,它们被视为简单的逐行域规则, 与 hosts 一样,只匹配完全相同的域。
|
|
@ -1,3 +1,13 @@
|
||||||
|
---
|
||||||
|
icon: material/new-box
|
||||||
|
---
|
||||||
|
|
||||||
|
!!! quote "Changes in sing-box 1.11.0"
|
||||||
|
|
||||||
|
:material-plus: [network_type](#network_type)
|
||||||
|
:material-plus: [network_is_expensive](#network_is_expensive)
|
||||||
|
:material-plus: [network_is_constrained](#network_is_constrained)
|
||||||
|
|
||||||
### Structure
|
### Structure
|
||||||
|
|
||||||
!!! question "Since sing-box 1.8.0"
|
!!! question "Since sing-box 1.8.0"
|
||||||
|
@ -63,6 +73,11 @@
|
||||||
"package_name": [
|
"package_name": [
|
||||||
"com.termux"
|
"com.termux"
|
||||||
],
|
],
|
||||||
|
"network_type": [
|
||||||
|
"wifi"
|
||||||
|
],
|
||||||
|
"network_is_expensive": false,
|
||||||
|
"network_is_constrained": false,
|
||||||
"wifi_ssid": [
|
"wifi_ssid": [
|
||||||
"My WIFI"
|
"My WIFI"
|
||||||
],
|
],
|
||||||
|
@ -177,6 +192,39 @@ Match process path using regular expression.
|
||||||
|
|
||||||
Match android package name.
|
Match android package name.
|
||||||
|
|
||||||
|
#### network_type
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.11.0"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
Only supported in graphical clients on Android and Apple platforms.
|
||||||
|
|
||||||
|
Match network type.
|
||||||
|
|
||||||
|
Available values: `wifi`, `cellular`, `ethernet` and `other`.
|
||||||
|
|
||||||
|
#### network_is_expensive
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.11.0"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
Only supported in graphical clients on Android and Apple platforms.
|
||||||
|
|
||||||
|
Match if network is considered Metered (on Android) or considered expensive,
|
||||||
|
such as Cellular or a Personal Hotspot (on Apple platforms).
|
||||||
|
|
||||||
|
#### network_is_constrained
|
||||||
|
|
||||||
|
!!! question "Since sing-box 1.11.0"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
Only supported in graphical clients on Apple platforms.
|
||||||
|
|
||||||
|
Match if network is in Low Data Mode.
|
||||||
|
|
||||||
#### wifi_ssid
|
#### wifi_ssid
|
||||||
|
|
||||||
!!! quote ""
|
!!! quote ""
|
||||||
|
|
258
docs/configuration/rule-set/headless-rule.zh.md
Normal file
258
docs/configuration/rule-set/headless-rule.zh.md
Normal file
|
@ -0,0 +1,258 @@
|
||||||
|
---
|
||||||
|
icon: material/new-box
|
||||||
|
---
|
||||||
|
|
||||||
|
!!! quote "sing-box 1.11.0 中的更改"
|
||||||
|
|
||||||
|
:material-plus: [network_type](#network_type)
|
||||||
|
:material-alert: [network_is_expensive](#network_is_expensive)
|
||||||
|
:material-alert: [network_is_constrained](#network_is_constrained)
|
||||||
|
|
||||||
|
### 结构
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.8.0 起"
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"rules": [
|
||||||
|
{
|
||||||
|
"query_type": [
|
||||||
|
"A",
|
||||||
|
"HTTPS",
|
||||||
|
32768
|
||||||
|
],
|
||||||
|
"network": [
|
||||||
|
"tcp"
|
||||||
|
],
|
||||||
|
"domain": [
|
||||||
|
"test.com"
|
||||||
|
],
|
||||||
|
"domain_suffix": [
|
||||||
|
".cn"
|
||||||
|
],
|
||||||
|
"domain_keyword": [
|
||||||
|
"test"
|
||||||
|
],
|
||||||
|
"domain_regex": [
|
||||||
|
"^stun\\..+"
|
||||||
|
],
|
||||||
|
"source_ip_cidr": [
|
||||||
|
"10.0.0.0/24",
|
||||||
|
"192.168.0.1"
|
||||||
|
],
|
||||||
|
"ip_cidr": [
|
||||||
|
"10.0.0.0/24",
|
||||||
|
"192.168.0.1"
|
||||||
|
],
|
||||||
|
"source_port": [
|
||||||
|
12345
|
||||||
|
],
|
||||||
|
"source_port_range": [
|
||||||
|
"1000:2000",
|
||||||
|
":3000",
|
||||||
|
"4000:"
|
||||||
|
],
|
||||||
|
"port": [
|
||||||
|
80,
|
||||||
|
443
|
||||||
|
],
|
||||||
|
"port_range": [
|
||||||
|
"1000:2000",
|
||||||
|
":3000",
|
||||||
|
"4000:"
|
||||||
|
],
|
||||||
|
"process_name": [
|
||||||
|
"curl"
|
||||||
|
],
|
||||||
|
"process_path": [
|
||||||
|
"/usr/bin/curl"
|
||||||
|
],
|
||||||
|
"process_path_regex": [
|
||||||
|
"^/usr/bin/.+"
|
||||||
|
],
|
||||||
|
"package_name": [
|
||||||
|
"com.termux"
|
||||||
|
],
|
||||||
|
"network_type": [
|
||||||
|
"wifi"
|
||||||
|
],
|
||||||
|
"network_is_expensive": false,
|
||||||
|
"network_is_constrained": false,
|
||||||
|
"wifi_ssid": [
|
||||||
|
"My WIFI"
|
||||||
|
],
|
||||||
|
"wifi_bssid": [
|
||||||
|
"00:00:00:00:00:00"
|
||||||
|
],
|
||||||
|
"invert": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "logical",
|
||||||
|
"mode": "and",
|
||||||
|
"rules": [],
|
||||||
|
"invert": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
|
||||||
|
当内容只有一项时,可以忽略 JSON 数组 [] 标签。
|
||||||
|
|
||||||
|
### Default Fields
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
|
||||||
|
默认规则使用以下匹配逻辑:
|
||||||
|
(`domain` || `domain_suffix` || `domain_keyword` || `domain_regex` || `ip_cidr`) &&
|
||||||
|
(`port` || `port_range`) &&
|
||||||
|
(`source_port` || `source_port_range`) &&
|
||||||
|
`other fields`
|
||||||
|
|
||||||
|
#### query_type
|
||||||
|
|
||||||
|
DNS 查询类型。值可以为整数或者类型名称字符串。
|
||||||
|
|
||||||
|
#### network
|
||||||
|
|
||||||
|
`tcp` 或 `udp`。
|
||||||
|
|
||||||
|
#### domain
|
||||||
|
|
||||||
|
匹配完整域名。
|
||||||
|
|
||||||
|
#### domain_suffix
|
||||||
|
|
||||||
|
匹配域名后缀。
|
||||||
|
|
||||||
|
#### domain_keyword
|
||||||
|
|
||||||
|
匹配域名关键字。
|
||||||
|
|
||||||
|
#### domain_regex
|
||||||
|
|
||||||
|
匹配域名正则表达式。
|
||||||
|
|
||||||
|
#### source_ip_cidr
|
||||||
|
|
||||||
|
匹配源 IP CIDR。
|
||||||
|
|
||||||
|
#### ip_cidr
|
||||||
|
|
||||||
|
匹配 IP CIDR。
|
||||||
|
|
||||||
|
#### source_port
|
||||||
|
|
||||||
|
匹配源端口。
|
||||||
|
|
||||||
|
#### source_port_range
|
||||||
|
|
||||||
|
匹配源端口范围。
|
||||||
|
|
||||||
|
#### port
|
||||||
|
|
||||||
|
匹配端口。
|
||||||
|
|
||||||
|
#### port_range
|
||||||
|
|
||||||
|
匹配端口范围。
|
||||||
|
|
||||||
|
#### process_name
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅支持 Linux、Windows 和 macOS。
|
||||||
|
|
||||||
|
匹配进程名称。
|
||||||
|
|
||||||
|
#### process_path
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅支持 Linux、Windows 和 macOS.
|
||||||
|
|
||||||
|
匹配进程路径。
|
||||||
|
|
||||||
|
#### process_path_regex
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.10.0 起"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅支持 Linux、Windows 和 macOS.
|
||||||
|
|
||||||
|
使用正则表达式匹配进程路径。
|
||||||
|
|
||||||
|
#### package_name
|
||||||
|
|
||||||
|
匹配 Android 应用包名。
|
||||||
|
|
||||||
|
#### network_type
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.11.0 起"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
|
匹配网络类型。
|
||||||
|
|
||||||
|
Available values: `wifi`, `cellular`, `ethernet` and `other`.
|
||||||
|
|
||||||
|
#### network_is_expensive
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.11.0 起"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
|
匹配如果网络被视为计费 (在 Android) 或被视为昂贵,
|
||||||
|
像蜂窝网络或个人热点 (在 Apple 平台)。
|
||||||
|
|
||||||
|
#### network_is_constrained
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.11.0 起"
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅在 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
|
匹配如果网络在低数据模式下。
|
||||||
|
|
||||||
|
#### wifi_ssid
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
|
匹配 WiFi SSID。
|
||||||
|
|
||||||
|
#### wifi_bssid
|
||||||
|
|
||||||
|
!!! quote ""
|
||||||
|
|
||||||
|
仅在 Android 与 Apple 平台图形客户端中支持。
|
||||||
|
|
||||||
|
#### invert
|
||||||
|
|
||||||
|
反选匹配结果。
|
||||||
|
|
||||||
|
### 逻辑字段
|
||||||
|
|
||||||
|
#### type
|
||||||
|
|
||||||
|
`logical`
|
||||||
|
|
||||||
|
#### mode
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
`and` 或 `or`
|
||||||
|
|
||||||
|
#### rules
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
包括的规则。
|
|
@ -74,7 +74,7 @@ Tag of rule-set.
|
||||||
|
|
||||||
==Required==
|
==Required==
|
||||||
|
|
||||||
List of [Headless Rule](./headless-rule.md/).
|
List of [Headless Rule](../headless-rule/).
|
||||||
|
|
||||||
### Local or Remote Fields
|
### Local or Remote Fields
|
||||||
|
|
||||||
|
|
117
docs/configuration/rule-set/index.zh.md
Normal file
117
docs/configuration/rule-set/index.zh.md
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
---
|
||||||
|
icon: material/new-box
|
||||||
|
---
|
||||||
|
|
||||||
|
!!! quote "sing-box 1.10.0 中的更改"
|
||||||
|
|
||||||
|
:material-plus: `type: inline`
|
||||||
|
|
||||||
|
# 规则集
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.8.0 起"
|
||||||
|
|
||||||
|
### 结构
|
||||||
|
|
||||||
|
=== "内联"
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.10.0 起"
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "inline", // 可选
|
||||||
|
"tag": "",
|
||||||
|
"rules": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "本地文件"
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "local",
|
||||||
|
"tag": "",
|
||||||
|
"format": "source", // or binary
|
||||||
|
"path": ""
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "远程文件"
|
||||||
|
|
||||||
|
!!! info ""
|
||||||
|
|
||||||
|
远程规则集将被缓存如果 `experimental.cache_file.enabled` 已启用。
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "remote",
|
||||||
|
"tag": "",
|
||||||
|
"format": "source", // or binary
|
||||||
|
"url": "",
|
||||||
|
"download_detour": "", // 可选
|
||||||
|
"update_interval": "" // 可选
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 字段
|
||||||
|
|
||||||
|
#### type
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
规则集类型, `local` 或 `remote`。
|
||||||
|
|
||||||
|
#### tag
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
规则集的标签。
|
||||||
|
|
||||||
|
### 内联字段
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.10.0 起"
|
||||||
|
|
||||||
|
#### rules
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
一组 [无头规则](../headless-rule/).
|
||||||
|
|
||||||
|
### 本地或远程字段
|
||||||
|
|
||||||
|
#### format
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
规则集格式, `source` 或 `binary`。
|
||||||
|
|
||||||
|
### 本地字段
|
||||||
|
|
||||||
|
#### path
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
!!! note ""
|
||||||
|
|
||||||
|
自 sing-box 1.10.0 起,文件更改时将自动重新加载。
|
||||||
|
|
||||||
|
规则集的文件路径。
|
||||||
|
|
||||||
|
### 远程字段
|
||||||
|
|
||||||
|
#### url
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
规则集的下载 URL。
|
||||||
|
|
||||||
|
#### download_detour
|
||||||
|
|
||||||
|
用于下载规则集的出站的标签。
|
||||||
|
|
||||||
|
如果为空,将使用默认出站。
|
||||||
|
|
||||||
|
#### update_interval
|
||||||
|
|
||||||
|
规则集的更新间隔。
|
||||||
|
|
||||||
|
默认使用 `1d`。
|
|
@ -4,6 +4,10 @@ icon: material/new-box
|
||||||
|
|
||||||
# Source Format
|
# Source Format
|
||||||
|
|
||||||
|
!!! quote "Changes in sing-box 1.11.0"
|
||||||
|
|
||||||
|
:material-plus: version `3`
|
||||||
|
|
||||||
!!! quote "Changes in sing-box 1.10.0"
|
!!! quote "Changes in sing-box 1.10.0"
|
||||||
|
|
||||||
:material-plus: version `2`
|
:material-plus: version `2`
|
||||||
|
@ -14,7 +18,7 @@ icon: material/new-box
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"version": 2,
|
"version": 3,
|
||||||
"rules": []
|
"rules": []
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -29,19 +33,14 @@ Use `sing-box rule-set compile [--output <file-name>.srs] <file-name>.json` to c
|
||||||
|
|
||||||
==Required==
|
==Required==
|
||||||
|
|
||||||
Version of rule-set, one of `1` or `2`.
|
Version of rule-set.
|
||||||
|
|
||||||
* 1: Initial rule-set version, since sing-box 1.8.0.
|
* 1: sing-box 1.8.0: Initial rule-set version.
|
||||||
* 2: Optimized memory usages of `domain_suffix` rules.
|
* 2: sing-box 1.10.0: Optimized memory usages of `domain_suffix` rules in binary rule-sets.
|
||||||
|
* 3: sing-box 1.11.0: Added `network_type`, `network_is_expensive` and `network_is_constrainted` rule items.
|
||||||
The new rule-set version `2` does not make any changes to the format, only affecting `binary` rule-sets compiled by command `rule-set compile`
|
|
||||||
|
|
||||||
Since 1.10.0, the optimization is always applied to `source` rule-sets even if version is set to `1`.
|
|
||||||
|
|
||||||
It is recommended to upgrade to `2` after sing-box 1.10.0 becomes a stable version.
|
|
||||||
|
|
||||||
#### rules
|
#### rules
|
||||||
|
|
||||||
==Required==
|
==Required==
|
||||||
|
|
||||||
List of [Headless Rule](./headless-rule.md/).
|
List of [Headless Rule](../headless-rule/).
|
||||||
|
|
46
docs/configuration/rule-set/source-format.zh.md
Normal file
46
docs/configuration/rule-set/source-format.zh.md
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
---
|
||||||
|
icon: material/new-box
|
||||||
|
---
|
||||||
|
|
||||||
|
# 源文件格式
|
||||||
|
|
||||||
|
!!! quote "sing-box 1.11.0 中的更改"
|
||||||
|
|
||||||
|
:material-plus: version `3`
|
||||||
|
|
||||||
|
!!! quote "sing-box 1.10.0 中的更改"
|
||||||
|
|
||||||
|
:material-plus: version `2`
|
||||||
|
|
||||||
|
!!! question "自 sing-box 1.8.0 起"
|
||||||
|
|
||||||
|
### 结构
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"rules": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 编译
|
||||||
|
|
||||||
|
使用 `sing-box rule-set compile [--output <file-name>.srs] <file-name>.json` 以编译源文件为二进制规则集。
|
||||||
|
|
||||||
|
### 字段
|
||||||
|
|
||||||
|
#### version
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
规则集版本。
|
||||||
|
|
||||||
|
* 1: sing-box 1.8.0: 初始规则集版本。
|
||||||
|
* 2: sing-box 1.10.0: 优化了二进制规则集中 `domain_suffix` 规则的内存使用。
|
||||||
|
* 3: sing-box 1.11.0: 添加了 `network_type`、 `network_is_expensive` 和 `network_is_constrainted` 规则项。
|
||||||
|
|
||||||
|
#### rules
|
||||||
|
|
||||||
|
==必填==
|
||||||
|
|
||||||
|
一组 [无头规则](../headless-rule/).
|
|
@ -95,6 +95,9 @@ type RawDefaultRule struct {
|
||||||
User badoption.Listable[string] `json:"user,omitempty"`
|
User badoption.Listable[string] `json:"user,omitempty"`
|
||||||
UserID badoption.Listable[int32] `json:"user_id,omitempty"`
|
UserID badoption.Listable[int32] `json:"user_id,omitempty"`
|
||||||
ClashMode string `json:"clash_mode,omitempty"`
|
ClashMode string `json:"clash_mode,omitempty"`
|
||||||
|
NetworkType badoption.Listable[string] `json:"network_type,omitempty"`
|
||||||
|
NetworkIsExpensive bool `json:"network_is_expensive,omitempty"`
|
||||||
|
NetworkIsConstrained bool `json:"network_is_constrained,omitempty"`
|
||||||
WIFISSID badoption.Listable[string] `json:"wifi_ssid,omitempty"`
|
WIFISSID badoption.Listable[string] `json:"wifi_ssid,omitempty"`
|
||||||
WIFIBSSID badoption.Listable[string] `json:"wifi_bssid,omitempty"`
|
WIFIBSSID badoption.Listable[string] `json:"wifi_bssid,omitempty"`
|
||||||
RuleSet badoption.Listable[string] `json:"rule_set,omitempty"`
|
RuleSet badoption.Listable[string] `json:"rule_set,omitempty"`
|
||||||
|
|
|
@ -97,6 +97,9 @@ type RawDefaultDNSRule struct {
|
||||||
UserID badoption.Listable[int32] `json:"user_id,omitempty"`
|
UserID badoption.Listable[int32] `json:"user_id,omitempty"`
|
||||||
Outbound badoption.Listable[string] `json:"outbound,omitempty"`
|
Outbound badoption.Listable[string] `json:"outbound,omitempty"`
|
||||||
ClashMode string `json:"clash_mode,omitempty"`
|
ClashMode string `json:"clash_mode,omitempty"`
|
||||||
|
NetworkType badoption.Listable[string] `json:"network_type,omitempty"`
|
||||||
|
NetworkIsExpensive bool `json:"network_is_expensive,omitempty"`
|
||||||
|
NetworkIsConstrained bool `json:"network_is_constrained,omitempty"`
|
||||||
WIFISSID badoption.Listable[string] `json:"wifi_ssid,omitempty"`
|
WIFISSID badoption.Listable[string] `json:"wifi_ssid,omitempty"`
|
||||||
WIFIBSSID badoption.Listable[string] `json:"wifi_bssid,omitempty"`
|
WIFIBSSID badoption.Listable[string] `json:"wifi_bssid,omitempty"`
|
||||||
RuleSet badoption.Listable[string] `json:"rule_set,omitempty"`
|
RuleSet badoption.Listable[string] `json:"rule_set,omitempty"`
|
||||||
|
|
|
@ -146,25 +146,28 @@ func (r HeadlessRule) IsValid() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type DefaultHeadlessRule struct {
|
type DefaultHeadlessRule struct {
|
||||||
QueryType badoption.Listable[DNSQueryType] `json:"query_type,omitempty"`
|
QueryType badoption.Listable[DNSQueryType] `json:"query_type,omitempty"`
|
||||||
Network badoption.Listable[string] `json:"network,omitempty"`
|
Network badoption.Listable[string] `json:"network,omitempty"`
|
||||||
Domain badoption.Listable[string] `json:"domain,omitempty"`
|
Domain badoption.Listable[string] `json:"domain,omitempty"`
|
||||||
DomainSuffix badoption.Listable[string] `json:"domain_suffix,omitempty"`
|
DomainSuffix badoption.Listable[string] `json:"domain_suffix,omitempty"`
|
||||||
DomainKeyword badoption.Listable[string] `json:"domain_keyword,omitempty"`
|
DomainKeyword badoption.Listable[string] `json:"domain_keyword,omitempty"`
|
||||||
DomainRegex badoption.Listable[string] `json:"domain_regex,omitempty"`
|
DomainRegex badoption.Listable[string] `json:"domain_regex,omitempty"`
|
||||||
SourceIPCIDR badoption.Listable[string] `json:"source_ip_cidr,omitempty"`
|
SourceIPCIDR badoption.Listable[string] `json:"source_ip_cidr,omitempty"`
|
||||||
IPCIDR badoption.Listable[string] `json:"ip_cidr,omitempty"`
|
IPCIDR badoption.Listable[string] `json:"ip_cidr,omitempty"`
|
||||||
SourcePort badoption.Listable[uint16] `json:"source_port,omitempty"`
|
SourcePort badoption.Listable[uint16] `json:"source_port,omitempty"`
|
||||||
SourcePortRange badoption.Listable[string] `json:"source_port_range,omitempty"`
|
SourcePortRange badoption.Listable[string] `json:"source_port_range,omitempty"`
|
||||||
Port badoption.Listable[uint16] `json:"port,omitempty"`
|
Port badoption.Listable[uint16] `json:"port,omitempty"`
|
||||||
PortRange badoption.Listable[string] `json:"port_range,omitempty"`
|
PortRange badoption.Listable[string] `json:"port_range,omitempty"`
|
||||||
ProcessName badoption.Listable[string] `json:"process_name,omitempty"`
|
ProcessName badoption.Listable[string] `json:"process_name,omitempty"`
|
||||||
ProcessPath badoption.Listable[string] `json:"process_path,omitempty"`
|
ProcessPath badoption.Listable[string] `json:"process_path,omitempty"`
|
||||||
ProcessPathRegex badoption.Listable[string] `json:"process_path_regex,omitempty"`
|
ProcessPathRegex badoption.Listable[string] `json:"process_path_regex,omitempty"`
|
||||||
PackageName badoption.Listable[string] `json:"package_name,omitempty"`
|
PackageName badoption.Listable[string] `json:"package_name,omitempty"`
|
||||||
WIFISSID badoption.Listable[string] `json:"wifi_ssid,omitempty"`
|
NetworkType badoption.Listable[string] `json:"network_type,omitempty"`
|
||||||
WIFIBSSID badoption.Listable[string] `json:"wifi_bssid,omitempty"`
|
NetworkIsExpensive bool `json:"network_is_expensive,omitempty"`
|
||||||
Invert bool `json:"invert,omitempty"`
|
NetworkIsConstrained bool `json:"network_is_constrained,omitempty"`
|
||||||
|
WIFISSID badoption.Listable[string] `json:"wifi_ssid,omitempty"`
|
||||||
|
WIFIBSSID badoption.Listable[string] `json:"wifi_bssid,omitempty"`
|
||||||
|
Invert bool `json:"invert,omitempty"`
|
||||||
|
|
||||||
DomainMatcher *domain.Matcher `json:"-"`
|
DomainMatcher *domain.Matcher `json:"-"`
|
||||||
SourceIPSet *netipx.IPSet `json:"-"`
|
SourceIPSet *netipx.IPSet `json:"-"`
|
||||||
|
@ -200,7 +203,7 @@ type PlainRuleSetCompat _PlainRuleSetCompat
|
||||||
func (r PlainRuleSetCompat) MarshalJSON() ([]byte, error) {
|
func (r PlainRuleSetCompat) MarshalJSON() ([]byte, error) {
|
||||||
var v any
|
var v any
|
||||||
switch r.Version {
|
switch r.Version {
|
||||||
case C.RuleSetVersion1, C.RuleSetVersion2:
|
case C.RuleSetVersion1, C.RuleSetVersion2, C.RuleSetVersion3:
|
||||||
v = r.Options
|
v = r.Options
|
||||||
default:
|
default:
|
||||||
return nil, E.New("unknown rule-set version: ", r.Version)
|
return nil, E.New("unknown rule-set version: ", r.Version)
|
||||||
|
@ -215,7 +218,7 @@ func (r *PlainRuleSetCompat) UnmarshalJSON(bytes []byte) error {
|
||||||
}
|
}
|
||||||
var v any
|
var v any
|
||||||
switch r.Version {
|
switch r.Version {
|
||||||
case C.RuleSetVersion1, C.RuleSetVersion2:
|
case C.RuleSetVersion1, C.RuleSetVersion2, C.RuleSetVersion3:
|
||||||
v = &r.Options
|
v = &r.Options
|
||||||
case 0:
|
case 0:
|
||||||
return E.New("missing rule-set version")
|
return E.New("missing rule-set version")
|
||||||
|
@ -231,7 +234,7 @@ func (r *PlainRuleSetCompat) UnmarshalJSON(bytes []byte) error {
|
||||||
|
|
||||||
func (r PlainRuleSetCompat) Upgrade() (PlainRuleSet, error) {
|
func (r PlainRuleSetCompat) Upgrade() (PlainRuleSet, error) {
|
||||||
switch r.Version {
|
switch r.Version {
|
||||||
case C.RuleSetVersion1, C.RuleSetVersion2:
|
case C.RuleSetVersion1, C.RuleSetVersion2, C.RuleSetVersion3:
|
||||||
default:
|
default:
|
||||||
return PlainRuleSet{}, E.New("unknown rule-set version: " + F.ToString(r.Version))
|
return PlainRuleSet{}, E.New("unknown rule-set version: " + F.ToString(r.Version))
|
||||||
}
|
}
|
||||||
|
|
|
@ -223,6 +223,21 @@ func NewDefaultRule(ctx context.Context, logger log.ContextLogger, options optio
|
||||||
rule.items = append(rule.items, item)
|
rule.items = append(rule.items, item)
|
||||||
rule.allItems = append(rule.allItems, item)
|
rule.allItems = append(rule.allItems, item)
|
||||||
}
|
}
|
||||||
|
if len(options.NetworkType) > 0 {
|
||||||
|
item := NewNetworkTypeItem(networkManager, options.NetworkType)
|
||||||
|
rule.items = append(rule.items, item)
|
||||||
|
rule.allItems = append(rule.allItems, item)
|
||||||
|
}
|
||||||
|
if options.NetworkIsExpensive {
|
||||||
|
item := NewNetworkIsExpensiveItem(networkManager)
|
||||||
|
rule.items = append(rule.items, item)
|
||||||
|
rule.allItems = append(rule.allItems, item)
|
||||||
|
}
|
||||||
|
if options.NetworkIsConstrained {
|
||||||
|
item := NewNetworkIsConstrainedItem(networkManager)
|
||||||
|
rule.items = append(rule.items, item)
|
||||||
|
rule.allItems = append(rule.allItems, item)
|
||||||
|
}
|
||||||
if len(options.WIFISSID) > 0 {
|
if len(options.WIFISSID) > 0 {
|
||||||
item := NewWIFISSIDItem(networkManager, options.WIFISSID)
|
item := NewWIFISSIDItem(networkManager, options.WIFISSID)
|
||||||
rule.items = append(rule.items, item)
|
rule.items = append(rule.items, item)
|
||||||
|
|
|
@ -220,6 +220,21 @@ func NewDefaultDNSRule(ctx context.Context, logger log.ContextLogger, options op
|
||||||
rule.items = append(rule.items, item)
|
rule.items = append(rule.items, item)
|
||||||
rule.allItems = append(rule.allItems, item)
|
rule.allItems = append(rule.allItems, item)
|
||||||
}
|
}
|
||||||
|
if len(options.NetworkType) > 0 {
|
||||||
|
item := NewNetworkTypeItem(networkManager, options.NetworkType)
|
||||||
|
rule.items = append(rule.items, item)
|
||||||
|
rule.allItems = append(rule.allItems, item)
|
||||||
|
}
|
||||||
|
if options.NetworkIsExpensive {
|
||||||
|
item := NewNetworkIsExpensiveItem(networkManager)
|
||||||
|
rule.items = append(rule.items, item)
|
||||||
|
rule.allItems = append(rule.allItems, item)
|
||||||
|
}
|
||||||
|
if options.NetworkIsConstrained {
|
||||||
|
item := NewNetworkIsConstrainedItem(networkManager)
|
||||||
|
rule.items = append(rule.items, item)
|
||||||
|
rule.allItems = append(rule.allItems, item)
|
||||||
|
}
|
||||||
if len(options.WIFISSID) > 0 {
|
if len(options.WIFISSID) > 0 {
|
||||||
item := NewWIFISSIDItem(networkManager, options.WIFISSID)
|
item := NewWIFISSIDItem(networkManager, options.WIFISSID)
|
||||||
rule.items = append(rule.items, item)
|
rule.items = append(rule.items, item)
|
||||||
|
|
|
@ -140,18 +140,33 @@ func NewDefaultHeadlessRule(ctx context.Context, options option.DefaultHeadlessR
|
||||||
rule.items = append(rule.items, item)
|
rule.items = append(rule.items, item)
|
||||||
rule.allItems = append(rule.allItems, item)
|
rule.allItems = append(rule.allItems, item)
|
||||||
}
|
}
|
||||||
if len(options.WIFISSID) > 0 {
|
if networkManager != nil {
|
||||||
if networkManager != nil {
|
if len(options.NetworkType) > 0 {
|
||||||
item := NewWIFISSIDItem(networkManager, options.WIFISSID)
|
item := NewNetworkTypeItem(networkManager, options.NetworkType)
|
||||||
rule.items = append(rule.items, item)
|
rule.items = append(rule.items, item)
|
||||||
rule.allItems = append(rule.allItems, item)
|
rule.allItems = append(rule.allItems, item)
|
||||||
}
|
}
|
||||||
}
|
if options.NetworkIsExpensive {
|
||||||
if len(options.WIFIBSSID) > 0 {
|
item := NewNetworkIsExpensiveItem(networkManager)
|
||||||
if networkManager != nil {
|
rule.items = append(rule.items, item)
|
||||||
|
rule.allItems = append(rule.allItems, item)
|
||||||
|
}
|
||||||
|
if options.NetworkIsConstrained {
|
||||||
|
item := NewNetworkIsConstrainedItem(networkManager)
|
||||||
|
rule.items = append(rule.items, item)
|
||||||
|
rule.allItems = append(rule.allItems, item)
|
||||||
|
}
|
||||||
|
if len(options.WIFISSID) > 0 {
|
||||||
|
item := NewWIFISSIDItem(networkManager, options.WIFISSID)
|
||||||
|
rule.items = append(rule.items, item)
|
||||||
|
rule.allItems = append(rule.allItems, item)
|
||||||
|
|
||||||
|
}
|
||||||
|
if len(options.WIFIBSSID) > 0 {
|
||||||
item := NewWIFIBSSIDItem(networkManager, options.WIFIBSSID)
|
item := NewWIFIBSSIDItem(networkManager, options.WIFIBSSID)
|
||||||
rule.items = append(rule.items, item)
|
rule.items = append(rule.items, item)
|
||||||
rule.allItems = append(rule.allItems, item)
|
rule.allItems = append(rule.allItems, item)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(options.AdGuardDomain) > 0 {
|
if len(options.AdGuardDomain) > 0 {
|
||||||
|
|
29
route/rule/rule_item_network_is_constrained.go
Normal file
29
route/rule/rule_item_network_is_constrained.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package rule
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ RuleItem = (*NetworkIsConstrainedItem)(nil)
|
||||||
|
|
||||||
|
type NetworkIsConstrainedItem struct {
|
||||||
|
networkManager adapter.NetworkManager
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNetworkIsConstrainedItem(networkManager adapter.NetworkManager) *NetworkIsConstrainedItem {
|
||||||
|
return &NetworkIsConstrainedItem{
|
||||||
|
networkManager: networkManager,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NetworkIsConstrainedItem) Match(metadata *adapter.InboundContext) bool {
|
||||||
|
networkInterface := r.networkManager.DefaultNetworkInterface()
|
||||||
|
if networkInterface == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return networkInterface.Constrained
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NetworkIsConstrainedItem) String() string {
|
||||||
|
return "network_is_expensive=true"
|
||||||
|
}
|
29
route/rule/rule_item_network_is_expensive.go
Normal file
29
route/rule/rule_item_network_is_expensive.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package rule
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ RuleItem = (*NetworkIsExpensiveItem)(nil)
|
||||||
|
|
||||||
|
type NetworkIsExpensiveItem struct {
|
||||||
|
networkManager adapter.NetworkManager
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNetworkIsExpensiveItem(networkManager adapter.NetworkManager) *NetworkIsExpensiveItem {
|
||||||
|
return &NetworkIsExpensiveItem{
|
||||||
|
networkManager: networkManager,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NetworkIsExpensiveItem) Match(metadata *adapter.InboundContext) bool {
|
||||||
|
networkInterface := r.networkManager.DefaultNetworkInterface()
|
||||||
|
if networkInterface == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return networkInterface.Expensive
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NetworkIsExpensiveItem) String() string {
|
||||||
|
return "network_is_expensive=true"
|
||||||
|
}
|
39
route/rule/rule_item_network_type.go
Normal file
39
route/rule/rule_item_network_type.go
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package rule
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
F "github.com/sagernet/sing/common/format"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ RuleItem = (*NetworkTypeItem)(nil)
|
||||||
|
|
||||||
|
type NetworkTypeItem struct {
|
||||||
|
networkManager adapter.NetworkManager
|
||||||
|
networkType []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNetworkTypeItem(networkManager adapter.NetworkManager, networkType []string) *NetworkTypeItem {
|
||||||
|
return &NetworkTypeItem{
|
||||||
|
networkManager: networkManager,
|
||||||
|
networkType: networkType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NetworkTypeItem) Match(metadata *adapter.InboundContext) bool {
|
||||||
|
networkInterface := r.networkManager.DefaultNetworkInterface()
|
||||||
|
if networkInterface == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return common.Contains(r.networkType, networkInterface.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *NetworkTypeItem) String() string {
|
||||||
|
if len(r.networkType) == 1 {
|
||||||
|
return F.ToString("network_type=", r.networkType[0])
|
||||||
|
} else {
|
||||||
|
return F.ToString("network_type=", "["+strings.Join(F.MapToString(r.networkType), " ")+"]")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue