github.com/sagernet/sing-box@v1.9.0-rc.20/option/rule_set.go (about)

     1  package option
     2  
     3  import (
     4  	"reflect"
     5  
     6  	C "github.com/sagernet/sing-box/constant"
     7  	"github.com/sagernet/sing/common"
     8  	"github.com/sagernet/sing/common/domain"
     9  	E "github.com/sagernet/sing/common/exceptions"
    10  	F "github.com/sagernet/sing/common/format"
    11  	"github.com/sagernet/sing/common/json"
    12  
    13  	"go4.org/netipx"
    14  )
    15  
    16  type _RuleSet struct {
    17  	Type          string        `json:"type"`
    18  	Tag           string        `json:"tag"`
    19  	Format        string        `json:"format"`
    20  	LocalOptions  LocalRuleSet  `json:"-"`
    21  	RemoteOptions RemoteRuleSet `json:"-"`
    22  }
    23  
    24  type RuleSet _RuleSet
    25  
    26  func (r RuleSet) MarshalJSON() ([]byte, error) {
    27  	var v any
    28  	switch r.Type {
    29  	case C.RuleSetTypeLocal:
    30  		v = r.LocalOptions
    31  	case C.RuleSetTypeRemote:
    32  		v = r.RemoteOptions
    33  	default:
    34  		return nil, E.New("unknown rule set type: " + r.Type)
    35  	}
    36  	return MarshallObjects((_RuleSet)(r), v)
    37  }
    38  
    39  func (r *RuleSet) UnmarshalJSON(bytes []byte) error {
    40  	err := json.Unmarshal(bytes, (*_RuleSet)(r))
    41  	if err != nil {
    42  		return err
    43  	}
    44  	if r.Tag == "" {
    45  		return E.New("missing tag")
    46  	}
    47  	switch r.Format {
    48  	case "":
    49  		return E.New("missing format")
    50  	case C.RuleSetFormatSource, C.RuleSetFormatBinary:
    51  	default:
    52  		return E.New("unknown rule set format: " + r.Format)
    53  	}
    54  	var v any
    55  	switch r.Type {
    56  	case C.RuleSetTypeLocal:
    57  		v = &r.LocalOptions
    58  	case C.RuleSetTypeRemote:
    59  		v = &r.RemoteOptions
    60  	case "":
    61  		return E.New("missing type")
    62  	default:
    63  		return E.New("unknown rule set type: " + r.Type)
    64  	}
    65  	err = UnmarshallExcluded(bytes, (*_RuleSet)(r), v)
    66  	if err != nil {
    67  		return err
    68  	}
    69  	return nil
    70  }
    71  
    72  type LocalRuleSet struct {
    73  	Path string `json:"path,omitempty"`
    74  }
    75  
    76  type RemoteRuleSet struct {
    77  	URL            string   `json:"url"`
    78  	DownloadDetour string   `json:"download_detour,omitempty"`
    79  	UpdateInterval Duration `json:"update_interval,omitempty"`
    80  }
    81  
    82  type _HeadlessRule struct {
    83  	Type           string              `json:"type,omitempty"`
    84  	DefaultOptions DefaultHeadlessRule `json:"-"`
    85  	LogicalOptions LogicalHeadlessRule `json:"-"`
    86  }
    87  
    88  type HeadlessRule _HeadlessRule
    89  
    90  func (r HeadlessRule) MarshalJSON() ([]byte, error) {
    91  	var v any
    92  	switch r.Type {
    93  	case C.RuleTypeDefault:
    94  		r.Type = ""
    95  		v = r.DefaultOptions
    96  	case C.RuleTypeLogical:
    97  		v = r.LogicalOptions
    98  	default:
    99  		return nil, E.New("unknown rule type: " + r.Type)
   100  	}
   101  	return MarshallObjects((_HeadlessRule)(r), v)
   102  }
   103  
   104  func (r *HeadlessRule) UnmarshalJSON(bytes []byte) error {
   105  	err := json.Unmarshal(bytes, (*_HeadlessRule)(r))
   106  	if err != nil {
   107  		return err
   108  	}
   109  	var v any
   110  	switch r.Type {
   111  	case "", C.RuleTypeDefault:
   112  		r.Type = C.RuleTypeDefault
   113  		v = &r.DefaultOptions
   114  	case C.RuleTypeLogical:
   115  		v = &r.LogicalOptions
   116  	default:
   117  		return E.New("unknown rule type: " + r.Type)
   118  	}
   119  	err = UnmarshallExcluded(bytes, (*_HeadlessRule)(r), v)
   120  	if err != nil {
   121  		return err
   122  	}
   123  	return nil
   124  }
   125  
   126  func (r HeadlessRule) IsValid() bool {
   127  	switch r.Type {
   128  	case C.RuleTypeDefault, "":
   129  		return r.DefaultOptions.IsValid()
   130  	case C.RuleTypeLogical:
   131  		return r.LogicalOptions.IsValid()
   132  	default:
   133  		panic("unknown rule type: " + r.Type)
   134  	}
   135  }
   136  
   137  type DefaultHeadlessRule struct {
   138  	QueryType       Listable[DNSQueryType] `json:"query_type,omitempty"`
   139  	Network         Listable[string]       `json:"network,omitempty"`
   140  	Domain          Listable[string]       `json:"domain,omitempty"`
   141  	DomainSuffix    Listable[string]       `json:"domain_suffix,omitempty"`
   142  	DomainKeyword   Listable[string]       `json:"domain_keyword,omitempty"`
   143  	DomainRegex     Listable[string]       `json:"domain_regex,omitempty"`
   144  	SourceIPCIDR    Listable[string]       `json:"source_ip_cidr,omitempty"`
   145  	IPCIDR          Listable[string]       `json:"ip_cidr,omitempty"`
   146  	SourcePort      Listable[uint16]       `json:"source_port,omitempty"`
   147  	SourcePortRange Listable[string]       `json:"source_port_range,omitempty"`
   148  	Port            Listable[uint16]       `json:"port,omitempty"`
   149  	PortRange       Listable[string]       `json:"port_range,omitempty"`
   150  	ProcessName     Listable[string]       `json:"process_name,omitempty"`
   151  	ProcessPath     Listable[string]       `json:"process_path,omitempty"`
   152  	PackageName     Listable[string]       `json:"package_name,omitempty"`
   153  	WIFISSID        Listable[string]       `json:"wifi_ssid,omitempty"`
   154  	WIFIBSSID       Listable[string]       `json:"wifi_bssid,omitempty"`
   155  	Invert          bool                   `json:"invert,omitempty"`
   156  
   157  	DomainMatcher *domain.Matcher `json:"-"`
   158  	SourceIPSet   *netipx.IPSet   `json:"-"`
   159  	IPSet         *netipx.IPSet   `json:"-"`
   160  }
   161  
   162  func (r DefaultHeadlessRule) IsValid() bool {
   163  	var defaultValue DefaultHeadlessRule
   164  	defaultValue.Invert = r.Invert
   165  	return !reflect.DeepEqual(r, defaultValue)
   166  }
   167  
   168  type LogicalHeadlessRule struct {
   169  	Mode   string         `json:"mode"`
   170  	Rules  []HeadlessRule `json:"rules,omitempty"`
   171  	Invert bool           `json:"invert,omitempty"`
   172  }
   173  
   174  func (r LogicalHeadlessRule) IsValid() bool {
   175  	return len(r.Rules) > 0 && common.All(r.Rules, HeadlessRule.IsValid)
   176  }
   177  
   178  type _PlainRuleSetCompat struct {
   179  	Version int          `json:"version"`
   180  	Options PlainRuleSet `json:"-"`
   181  }
   182  
   183  type PlainRuleSetCompat _PlainRuleSetCompat
   184  
   185  func (r PlainRuleSetCompat) MarshalJSON() ([]byte, error) {
   186  	var v any
   187  	switch r.Version {
   188  	case C.RuleSetVersion1:
   189  		v = r.Options
   190  	default:
   191  		return nil, E.New("unknown rule set version: ", r.Version)
   192  	}
   193  	return MarshallObjects((_PlainRuleSetCompat)(r), v)
   194  }
   195  
   196  func (r *PlainRuleSetCompat) UnmarshalJSON(bytes []byte) error {
   197  	err := json.Unmarshal(bytes, (*_PlainRuleSetCompat)(r))
   198  	if err != nil {
   199  		return err
   200  	}
   201  	var v any
   202  	switch r.Version {
   203  	case C.RuleSetVersion1:
   204  		v = &r.Options
   205  	case 0:
   206  		return E.New("missing rule set version")
   207  	default:
   208  		return E.New("unknown rule set version: ", r.Version)
   209  	}
   210  	err = UnmarshallExcluded(bytes, (*_PlainRuleSetCompat)(r), v)
   211  	if err != nil {
   212  		return err
   213  	}
   214  	return nil
   215  }
   216  
   217  func (r PlainRuleSetCompat) Upgrade() PlainRuleSet {
   218  	var result PlainRuleSet
   219  	switch r.Version {
   220  	case C.RuleSetVersion1:
   221  		result = r.Options
   222  	default:
   223  		panic("unknown rule set version: " + F.ToString(r.Version))
   224  	}
   225  	return result
   226  }
   227  
   228  type PlainRuleSet struct {
   229  	Rules []HeadlessRule `json:"rules,omitempty"`
   230  }