mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-21 16:11:32 +00:00
Add network_[type/is_expensive/is_constrained]
rule items
This commit is contained in:
parent
e81794bdf3
commit
ca558de0ef
|
@ -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 (
|
||||||
|
|
|
@ -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"`
|
||||||
|
|
|
@ -162,6 +162,9 @@ type DefaultHeadlessRule struct {
|
||||||
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"`
|
||||||
|
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"`
|
||||||
Invert bool `json:"invert,omitempty"`
|
Invert bool `json:"invert,omitempty"`
|
||||||
|
@ -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 := 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 {
|
||||||
item := NewWIFISSIDItem(networkManager, options.WIFISSID)
|
item := NewWIFISSIDItem(networkManager, options.WIFISSID)
|
||||||
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.WIFIBSSID) > 0 {
|
if len(options.WIFIBSSID) > 0 {
|
||||||
if networkManager != nil {
|
|
||||||
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