rule_set.go 6.0 KB

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