2023-06-07 12:28:21 +00:00
|
|
|
package route
|
|
|
|
|
|
|
|
import (
|
2023-12-01 05:24:12 +00:00
|
|
|
"io"
|
2023-06-07 12:28:21 +00:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/sagernet/sing-box/adapter"
|
|
|
|
C "github.com/sagernet/sing-box/constant"
|
|
|
|
"github.com/sagernet/sing/common"
|
|
|
|
F "github.com/sagernet/sing/common/format"
|
|
|
|
)
|
|
|
|
|
|
|
|
type abstractDefaultRule struct {
|
|
|
|
items []RuleItem
|
|
|
|
sourceAddressItems []RuleItem
|
|
|
|
sourcePortItems []RuleItem
|
|
|
|
destinationAddressItems []RuleItem
|
2024-02-03 09:45:27 +00:00
|
|
|
destinationIPCIDRItems []RuleItem
|
2023-06-07 12:28:21 +00:00
|
|
|
destinationPortItems []RuleItem
|
|
|
|
allItems []RuleItem
|
2023-12-01 05:24:12 +00:00
|
|
|
ruleSetItem RuleItem
|
2023-06-07 12:28:21 +00:00
|
|
|
invert bool
|
|
|
|
outbound string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *abstractDefaultRule) Type() string {
|
|
|
|
return C.RuleTypeDefault
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *abstractDefaultRule) Start() error {
|
|
|
|
for _, item := range r.allItems {
|
2024-06-24 01:49:15 +00:00
|
|
|
if starter, isStarter := item.(interface {
|
|
|
|
Start() error
|
|
|
|
}); isStarter {
|
|
|
|
err := starter.Start()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-06-07 12:28:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *abstractDefaultRule) Close() error {
|
|
|
|
for _, item := range r.allItems {
|
|
|
|
err := common.Close(item)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *abstractDefaultRule) UpdateGeosite() error {
|
|
|
|
for _, item := range r.allItems {
|
|
|
|
if geositeItem, isSite := item.(*GeositeItem); isSite {
|
|
|
|
err := geositeItem.Update()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *abstractDefaultRule) Match(metadata *adapter.InboundContext) bool {
|
2023-03-25 04:03:23 +00:00
|
|
|
if len(r.allItems) == 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-12-01 05:24:12 +00:00
|
|
|
if len(r.sourceAddressItems) > 0 && !metadata.SourceAddressMatch {
|
2024-02-03 09:45:27 +00:00
|
|
|
metadata.DidMatch = true
|
2023-06-07 12:28:21 +00:00
|
|
|
for _, item := range r.sourceAddressItems {
|
|
|
|
if item.Match(metadata) {
|
2023-12-01 05:24:12 +00:00
|
|
|
metadata.SourceAddressMatch = true
|
2023-06-07 12:28:21 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-14 05:01:57 +00:00
|
|
|
if len(r.sourcePortItems) > 0 && !metadata.SourcePortMatch {
|
2024-02-03 09:45:27 +00:00
|
|
|
metadata.DidMatch = true
|
2023-06-07 12:28:21 +00:00
|
|
|
for _, item := range r.sourcePortItems {
|
|
|
|
if item.Match(metadata) {
|
2023-12-01 05:24:12 +00:00
|
|
|
metadata.SourcePortMatch = true
|
2023-06-07 12:28:21 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-14 05:01:57 +00:00
|
|
|
if len(r.destinationAddressItems) > 0 && !metadata.DestinationAddressMatch {
|
2024-02-03 09:45:27 +00:00
|
|
|
metadata.DidMatch = true
|
2023-06-07 12:28:21 +00:00
|
|
|
for _, item := range r.destinationAddressItems {
|
|
|
|
if item.Match(metadata) {
|
2023-12-01 05:24:12 +00:00
|
|
|
metadata.DestinationAddressMatch = true
|
2023-06-07 12:28:21 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-03 09:45:27 +00:00
|
|
|
if !metadata.IgnoreDestinationIPCIDRMatch && len(r.destinationIPCIDRItems) > 0 && !metadata.DestinationAddressMatch {
|
|
|
|
metadata.DidMatch = true
|
|
|
|
for _, item := range r.destinationIPCIDRItems {
|
|
|
|
if item.Match(metadata) {
|
|
|
|
metadata.DestinationAddressMatch = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-14 05:01:57 +00:00
|
|
|
if len(r.destinationPortItems) > 0 && !metadata.DestinationPortMatch {
|
2024-02-03 09:45:27 +00:00
|
|
|
metadata.DidMatch = true
|
2023-06-07 12:28:21 +00:00
|
|
|
for _, item := range r.destinationPortItems {
|
|
|
|
if item.Match(metadata) {
|
2023-12-01 05:24:12 +00:00
|
|
|
metadata.DestinationPortMatch = true
|
2023-06-07 12:28:21 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2023-12-01 05:24:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, item := range r.items {
|
2024-02-03 09:45:27 +00:00
|
|
|
if _, isRuleSet := item.(*RuleSetItem); !isRuleSet {
|
|
|
|
metadata.DidMatch = true
|
|
|
|
}
|
2023-12-01 05:24:12 +00:00
|
|
|
if !item.Match(metadata) {
|
2023-06-07 12:28:21 +00:00
|
|
|
return r.invert
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-01 05:24:12 +00:00
|
|
|
if len(r.sourceAddressItems) > 0 && !metadata.SourceAddressMatch {
|
|
|
|
return r.invert
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(r.sourcePortItems) > 0 && !metadata.SourcePortMatch {
|
|
|
|
return r.invert
|
|
|
|
}
|
|
|
|
|
2024-02-03 09:45:27 +00:00
|
|
|
if ((!metadata.IgnoreDestinationIPCIDRMatch && len(r.destinationIPCIDRItems) > 0) || len(r.destinationAddressItems) > 0) && !metadata.DestinationAddressMatch {
|
2023-12-01 05:24:12 +00:00
|
|
|
return r.invert
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(r.destinationPortItems) > 0 && !metadata.DestinationPortMatch {
|
|
|
|
return r.invert
|
|
|
|
}
|
|
|
|
|
2024-02-03 09:45:27 +00:00
|
|
|
if !metadata.DidMatch {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-06-07 12:28:21 +00:00
|
|
|
return !r.invert
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *abstractDefaultRule) Outbound() string {
|
|
|
|
return r.outbound
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *abstractDefaultRule) String() string {
|
|
|
|
if !r.invert {
|
|
|
|
return strings.Join(F.MapToString(r.allItems), " ")
|
|
|
|
} else {
|
|
|
|
return "!(" + strings.Join(F.MapToString(r.allItems), " ") + ")"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type abstractLogicalRule struct {
|
2023-12-01 05:24:12 +00:00
|
|
|
rules []adapter.HeadlessRule
|
2023-06-07 12:28:21 +00:00
|
|
|
mode string
|
|
|
|
invert bool
|
|
|
|
outbound string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *abstractLogicalRule) Type() string {
|
|
|
|
return C.RuleTypeLogical
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *abstractLogicalRule) UpdateGeosite() error {
|
2023-12-01 05:24:12 +00:00
|
|
|
for _, rule := range common.FilterIsInstance(r.rules, func(it adapter.HeadlessRule) (adapter.Rule, bool) {
|
|
|
|
rule, loaded := it.(adapter.Rule)
|
|
|
|
return rule, loaded
|
|
|
|
}) {
|
2023-06-07 12:28:21 +00:00
|
|
|
err := rule.UpdateGeosite()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *abstractLogicalRule) Start() error {
|
2024-06-24 01:49:15 +00:00
|
|
|
for _, rule := range common.FilterIsInstance(r.rules, func(it adapter.HeadlessRule) (interface {
|
|
|
|
Start() error
|
|
|
|
}, bool,
|
|
|
|
) {
|
|
|
|
rule, loaded := it.(interface {
|
|
|
|
Start() error
|
|
|
|
})
|
2023-12-01 05:24:12 +00:00
|
|
|
return rule, loaded
|
|
|
|
}) {
|
2023-06-07 12:28:21 +00:00
|
|
|
err := rule.Start()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *abstractLogicalRule) Close() error {
|
2023-12-01 05:24:12 +00:00
|
|
|
for _, rule := range common.FilterIsInstance(r.rules, func(it adapter.HeadlessRule) (io.Closer, bool) {
|
|
|
|
rule, loaded := it.(io.Closer)
|
|
|
|
return rule, loaded
|
|
|
|
}) {
|
2023-06-07 12:28:21 +00:00
|
|
|
err := rule.Close()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *abstractLogicalRule) Match(metadata *adapter.InboundContext) bool {
|
|
|
|
if r.mode == C.LogicalTypeAnd {
|
2023-12-01 05:24:12 +00:00
|
|
|
return common.All(r.rules, func(it adapter.HeadlessRule) bool {
|
|
|
|
metadata.ResetRuleCache()
|
2023-06-07 12:28:21 +00:00
|
|
|
return it.Match(metadata)
|
|
|
|
}) != r.invert
|
|
|
|
} else {
|
2023-12-01 05:24:12 +00:00
|
|
|
return common.Any(r.rules, func(it adapter.HeadlessRule) bool {
|
|
|
|
metadata.ResetRuleCache()
|
2023-06-07 12:28:21 +00:00
|
|
|
return it.Match(metadata)
|
|
|
|
}) != r.invert
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *abstractLogicalRule) Outbound() string {
|
|
|
|
return r.outbound
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *abstractLogicalRule) String() string {
|
|
|
|
var op string
|
|
|
|
switch r.mode {
|
|
|
|
case C.LogicalTypeAnd:
|
|
|
|
op = "&&"
|
|
|
|
case C.LogicalTypeOr:
|
|
|
|
op = "||"
|
|
|
|
}
|
|
|
|
if !r.invert {
|
|
|
|
return strings.Join(F.MapToString(r.rules), " "+op+" ")
|
|
|
|
} else {
|
|
|
|
return "!(" + strings.Join(F.MapToString(r.rules), " "+op+" ") + ")"
|
|
|
|
}
|
|
|
|
}
|