1
0

rule.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. package route
  2. import (
  3. "strings"
  4. "github.com/sagernet/sing-box/adapter"
  5. C "github.com/sagernet/sing-box/constant"
  6. "github.com/sagernet/sing-box/log"
  7. "github.com/sagernet/sing-box/option"
  8. "github.com/sagernet/sing/common"
  9. E "github.com/sagernet/sing/common/exceptions"
  10. F "github.com/sagernet/sing/common/format"
  11. N "github.com/sagernet/sing/common/network"
  12. )
  13. func NewRule(router adapter.Router, logger log.ContextLogger, options option.Rule) (adapter.Rule, error) {
  14. switch options.Type {
  15. case "", C.RuleTypeDefault:
  16. if !options.DefaultOptions.IsValid() {
  17. return nil, E.New("missing conditions")
  18. }
  19. if options.DefaultOptions.Outbound == "" {
  20. return nil, E.New("missing outbound field")
  21. }
  22. return NewDefaultRule(router, logger, options.DefaultOptions)
  23. case C.RuleTypeLogical:
  24. if !options.LogicalOptions.IsValid() {
  25. return nil, E.New("missing conditions")
  26. }
  27. if options.LogicalOptions.Outbound == "" {
  28. return nil, E.New("missing outbound field")
  29. }
  30. return NewLogicalRule(router, logger, options.LogicalOptions)
  31. default:
  32. return nil, E.New("unknown rule type: ", options.Type)
  33. }
  34. }
  35. var _ adapter.Rule = (*DefaultRule)(nil)
  36. type DefaultRule struct {
  37. items []RuleItem
  38. sourceAddressItems []RuleItem
  39. sourcePortItems []RuleItem
  40. destinationAddressItems []RuleItem
  41. destinationPortItems []RuleItem
  42. allItems []RuleItem
  43. invert bool
  44. outbound string
  45. }
  46. type RuleItem interface {
  47. Match(metadata *adapter.InboundContext) bool
  48. String() string
  49. }
  50. func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options option.DefaultRule) (*DefaultRule, error) {
  51. rule := &DefaultRule{
  52. invert: options.Invert,
  53. outbound: options.Outbound,
  54. }
  55. if len(options.Inbound) > 0 {
  56. item := NewInboundRule(options.Inbound)
  57. rule.items = append(rule.items, item)
  58. rule.allItems = append(rule.allItems, item)
  59. }
  60. if options.IPVersion > 0 {
  61. switch options.IPVersion {
  62. case 4, 6:
  63. item := NewIPVersionItem(options.IPVersion == 6)
  64. rule.items = append(rule.items, item)
  65. rule.allItems = append(rule.allItems, item)
  66. default:
  67. return nil, E.New("invalid ip version: ", options.IPVersion)
  68. }
  69. }
  70. if options.Network != "" {
  71. switch options.Network {
  72. case N.NetworkTCP, N.NetworkUDP:
  73. item := NewNetworkItem(options.Network)
  74. rule.items = append(rule.items, item)
  75. rule.allItems = append(rule.allItems, item)
  76. default:
  77. return nil, E.New("invalid network: ", options.Network)
  78. }
  79. }
  80. if len(options.AuthUser) > 0 {
  81. item := NewAuthUserItem(options.AuthUser)
  82. rule.items = append(rule.items, item)
  83. rule.allItems = append(rule.allItems, item)
  84. }
  85. if len(options.Protocol) > 0 {
  86. item := NewProtocolItem(options.Protocol)
  87. rule.items = append(rule.items, item)
  88. rule.allItems = append(rule.allItems, item)
  89. }
  90. if len(options.Domain) > 0 || len(options.DomainSuffix) > 0 {
  91. item := NewDomainItem(options.Domain, options.DomainSuffix)
  92. rule.destinationAddressItems = append(rule.destinationAddressItems, item)
  93. rule.allItems = append(rule.allItems, item)
  94. }
  95. if len(options.DomainKeyword) > 0 {
  96. item := NewDomainKeywordItem(options.DomainKeyword)
  97. rule.destinationAddressItems = append(rule.destinationAddressItems, item)
  98. rule.allItems = append(rule.allItems, item)
  99. }
  100. if len(options.DomainRegex) > 0 {
  101. item, err := NewDomainRegexItem(options.DomainRegex)
  102. if err != nil {
  103. return nil, E.Cause(err, "domain_regex")
  104. }
  105. rule.destinationAddressItems = append(rule.destinationAddressItems, item)
  106. rule.allItems = append(rule.allItems, item)
  107. }
  108. if len(options.Geosite) > 0 {
  109. item := NewGeositeItem(router, logger, options.Geosite)
  110. rule.destinationAddressItems = append(rule.destinationAddressItems, item)
  111. rule.allItems = append(rule.allItems, item)
  112. }
  113. if len(options.SourceGeoIP) > 0 {
  114. item := NewGeoIPItem(router, logger, true, options.SourceGeoIP)
  115. rule.sourceAddressItems = append(rule.sourceAddressItems, item)
  116. rule.allItems = append(rule.allItems, item)
  117. }
  118. if len(options.GeoIP) > 0 {
  119. item := NewGeoIPItem(router, logger, false, options.GeoIP)
  120. rule.destinationAddressItems = append(rule.destinationAddressItems, item)
  121. rule.allItems = append(rule.allItems, item)
  122. }
  123. if len(options.SourceIPCIDR) > 0 {
  124. item, err := NewIPCIDRItem(true, options.SourceIPCIDR)
  125. if err != nil {
  126. return nil, E.Cause(err, "source_ipcidr")
  127. }
  128. rule.sourceAddressItems = append(rule.sourceAddressItems, item)
  129. rule.allItems = append(rule.allItems, item)
  130. }
  131. if len(options.IPCIDR) > 0 {
  132. item, err := NewIPCIDRItem(false, options.IPCIDR)
  133. if err != nil {
  134. return nil, E.Cause(err, "ipcidr")
  135. }
  136. rule.destinationAddressItems = append(rule.destinationAddressItems, item)
  137. rule.allItems = append(rule.allItems, item)
  138. }
  139. if len(options.SourcePort) > 0 {
  140. item := NewPortItem(true, options.SourcePort)
  141. rule.sourcePortItems = append(rule.sourcePortItems, item)
  142. rule.allItems = append(rule.allItems, item)
  143. }
  144. if len(options.SourcePortRange) > 0 {
  145. item, err := NewPortRangeItem(true, options.SourcePortRange)
  146. if err != nil {
  147. return nil, E.Cause(err, "source_port_range")
  148. }
  149. rule.sourcePortItems = append(rule.sourcePortItems, item)
  150. rule.allItems = append(rule.allItems, item)
  151. }
  152. if len(options.Port) > 0 {
  153. item := NewPortItem(false, options.Port)
  154. rule.destinationPortItems = append(rule.destinationPortItems, item)
  155. rule.allItems = append(rule.allItems, item)
  156. }
  157. if len(options.PortRange) > 0 {
  158. item, err := NewPortRangeItem(false, options.PortRange)
  159. if err != nil {
  160. return nil, E.Cause(err, "port_range")
  161. }
  162. rule.destinationPortItems = append(rule.destinationPortItems, item)
  163. rule.allItems = append(rule.allItems, item)
  164. }
  165. if len(options.ProcessName) > 0 {
  166. item := NewProcessItem(options.ProcessName)
  167. rule.items = append(rule.items, item)
  168. rule.allItems = append(rule.allItems, item)
  169. }
  170. if len(options.ProcessPath) > 0 {
  171. item := NewProcessPathItem(options.ProcessPath)
  172. rule.items = append(rule.items, item)
  173. rule.allItems = append(rule.allItems, item)
  174. }
  175. if len(options.PackageName) > 0 {
  176. item := NewPackageNameItem(options.PackageName)
  177. rule.items = append(rule.items, item)
  178. rule.allItems = append(rule.allItems, item)
  179. }
  180. if len(options.User) > 0 {
  181. item := NewUserItem(options.User)
  182. rule.items = append(rule.items, item)
  183. rule.allItems = append(rule.allItems, item)
  184. }
  185. if len(options.UserID) > 0 {
  186. item := NewUserIDItem(options.UserID)
  187. rule.items = append(rule.items, item)
  188. rule.allItems = append(rule.allItems, item)
  189. }
  190. if options.ClashMode != "" {
  191. item := NewClashModeItem(router, options.ClashMode)
  192. rule.items = append(rule.items, item)
  193. rule.allItems = append(rule.allItems, item)
  194. }
  195. return rule, nil
  196. }
  197. func (r *DefaultRule) Type() string {
  198. return C.RuleTypeDefault
  199. }
  200. func (r *DefaultRule) Start() error {
  201. for _, item := range r.allItems {
  202. err := common.Start(item)
  203. if err != nil {
  204. return err
  205. }
  206. }
  207. return nil
  208. }
  209. func (r *DefaultRule) Close() error {
  210. for _, item := range r.allItems {
  211. err := common.Close(item)
  212. if err != nil {
  213. return err
  214. }
  215. }
  216. return nil
  217. }
  218. func (r *DefaultRule) UpdateGeosite() error {
  219. for _, item := range r.allItems {
  220. if geositeItem, isSite := item.(*GeositeItem); isSite {
  221. err := geositeItem.Update()
  222. if err != nil {
  223. return err
  224. }
  225. }
  226. }
  227. return nil
  228. }
  229. func (r *DefaultRule) Match(metadata *adapter.InboundContext) bool {
  230. for _, item := range r.items {
  231. if !item.Match(metadata) {
  232. return r.invert
  233. }
  234. }
  235. if len(r.sourceAddressItems) > 0 {
  236. var sourceAddressMatch bool
  237. for _, item := range r.sourceAddressItems {
  238. if item.Match(metadata) {
  239. sourceAddressMatch = true
  240. break
  241. }
  242. }
  243. if !sourceAddressMatch {
  244. return r.invert
  245. }
  246. }
  247. if len(r.sourcePortItems) > 0 {
  248. var sourcePortMatch bool
  249. for _, item := range r.sourcePortItems {
  250. if item.Match(metadata) {
  251. sourcePortMatch = true
  252. break
  253. }
  254. }
  255. if !sourcePortMatch {
  256. return r.invert
  257. }
  258. }
  259. if len(r.destinationAddressItems) > 0 {
  260. var destinationAddressMatch bool
  261. for _, item := range r.destinationAddressItems {
  262. if item.Match(metadata) {
  263. destinationAddressMatch = true
  264. break
  265. }
  266. }
  267. if !destinationAddressMatch {
  268. return r.invert
  269. }
  270. }
  271. if len(r.destinationPortItems) > 0 {
  272. var destinationPortMatch bool
  273. for _, item := range r.destinationPortItems {
  274. if item.Match(metadata) {
  275. destinationPortMatch = true
  276. break
  277. }
  278. }
  279. if !destinationPortMatch {
  280. return r.invert
  281. }
  282. }
  283. return !r.invert
  284. }
  285. func (r *DefaultRule) Outbound() string {
  286. return r.outbound
  287. }
  288. func (r *DefaultRule) String() string {
  289. if !r.invert {
  290. return strings.Join(F.MapToString(r.allItems), " ")
  291. } else {
  292. return "!(" + strings.Join(F.MapToString(r.allItems), " ") + ")"
  293. }
  294. }
  295. var _ adapter.Rule = (*LogicalRule)(nil)
  296. type LogicalRule struct {
  297. mode string
  298. rules []*DefaultRule
  299. invert bool
  300. outbound string
  301. }
  302. func NewLogicalRule(router adapter.Router, logger log.ContextLogger, options option.LogicalRule) (*LogicalRule, error) {
  303. r := &LogicalRule{
  304. rules: make([]*DefaultRule, len(options.Rules)),
  305. invert: options.Invert,
  306. outbound: options.Outbound,
  307. }
  308. switch options.Mode {
  309. case C.LogicalTypeAnd:
  310. r.mode = C.LogicalTypeAnd
  311. case C.LogicalTypeOr:
  312. r.mode = C.LogicalTypeOr
  313. default:
  314. return nil, E.New("unknown logical mode: ", options.Mode)
  315. }
  316. for i, subRule := range options.Rules {
  317. rule, err := NewDefaultRule(router, logger, subRule)
  318. if err != nil {
  319. return nil, E.Cause(err, "sub rule[", i, "]")
  320. }
  321. r.rules[i] = rule
  322. }
  323. return r, nil
  324. }
  325. func (r *LogicalRule) Type() string {
  326. return C.RuleTypeLogical
  327. }
  328. func (r *LogicalRule) UpdateGeosite() error {
  329. for _, rule := range r.rules {
  330. err := rule.UpdateGeosite()
  331. if err != nil {
  332. return err
  333. }
  334. }
  335. return nil
  336. }
  337. func (r *LogicalRule) Start() error {
  338. for _, rule := range r.rules {
  339. err := rule.Start()
  340. if err != nil {
  341. return err
  342. }
  343. }
  344. return nil
  345. }
  346. func (r *LogicalRule) Close() error {
  347. for _, rule := range r.rules {
  348. err := rule.Close()
  349. if err != nil {
  350. return err
  351. }
  352. }
  353. return nil
  354. }
  355. func (r *LogicalRule) Match(metadata *adapter.InboundContext) bool {
  356. if r.mode == C.LogicalTypeAnd {
  357. return common.All(r.rules, func(it *DefaultRule) bool {
  358. return it.Match(metadata)
  359. }) != r.invert
  360. } else {
  361. return common.Any(r.rules, func(it *DefaultRule) bool {
  362. return it.Match(metadata)
  363. }) != r.invert
  364. }
  365. }
  366. func (r *LogicalRule) Outbound() string {
  367. return r.outbound
  368. }
  369. func (r *LogicalRule) String() string {
  370. var op string
  371. switch r.mode {
  372. case C.LogicalTypeAnd:
  373. op = "&&"
  374. case C.LogicalTypeOr:
  375. op = "||"
  376. }
  377. if !r.invert {
  378. return strings.Join(F.MapToString(r.rules), " "+op+" ")
  379. } else {
  380. return "!(" + strings.Join(F.MapToString(r.rules), " "+op+" ") + ")"
  381. }
  382. }