rule_set.go 7.3 KB

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