rule_set.go 6.6 KB

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