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 }