github.com/sagernet/sing-box@v1.9.0-rc.20/route/rule_abstract.go (about)

     1  package route
     2  
     3  import (
     4  	"io"
     5  	"strings"
     6  
     7  	"github.com/sagernet/sing-box/adapter"
     8  	C "github.com/sagernet/sing-box/constant"
     9  	"github.com/sagernet/sing/common"
    10  	F "github.com/sagernet/sing/common/format"
    11  )
    12  
    13  type abstractDefaultRule struct {
    14  	items                   []RuleItem
    15  	sourceAddressItems      []RuleItem
    16  	sourcePortItems         []RuleItem
    17  	destinationAddressItems []RuleItem
    18  	destinationIPCIDRItems  []RuleItem
    19  	destinationPortItems    []RuleItem
    20  	allItems                []RuleItem
    21  	ruleSetItem             RuleItem
    22  	invert                  bool
    23  	outbound                string
    24  }
    25  
    26  func (r *abstractDefaultRule) Type() string {
    27  	return C.RuleTypeDefault
    28  }
    29  
    30  func (r *abstractDefaultRule) Start() error {
    31  	for _, item := range r.allItems {
    32  		err := common.Start(item)
    33  		if err != nil {
    34  			return err
    35  		}
    36  	}
    37  	return nil
    38  }
    39  
    40  func (r *abstractDefaultRule) Close() error {
    41  	for _, item := range r.allItems {
    42  		err := common.Close(item)
    43  		if err != nil {
    44  			return err
    45  		}
    46  	}
    47  	return nil
    48  }
    49  
    50  func (r *abstractDefaultRule) UpdateGeosite() error {
    51  	for _, item := range r.allItems {
    52  		if geositeItem, isSite := item.(*GeositeItem); isSite {
    53  			err := geositeItem.Update()
    54  			if err != nil {
    55  				return err
    56  			}
    57  		}
    58  	}
    59  	return nil
    60  }
    61  
    62  func (r *abstractDefaultRule) Match(metadata *adapter.InboundContext) bool {
    63  	if len(r.allItems) == 0 {
    64  		return true
    65  	}
    66  
    67  	if len(r.sourceAddressItems) > 0 && !metadata.SourceAddressMatch {
    68  		metadata.DidMatch = true
    69  		for _, item := range r.sourceAddressItems {
    70  			if item.Match(metadata) {
    71  				metadata.SourceAddressMatch = true
    72  				break
    73  			}
    74  		}
    75  	}
    76  
    77  	if len(r.sourcePortItems) > 0 && !metadata.SourcePortMatch {
    78  		metadata.DidMatch = true
    79  		for _, item := range r.sourcePortItems {
    80  			if item.Match(metadata) {
    81  				metadata.SourcePortMatch = true
    82  				break
    83  			}
    84  		}
    85  	}
    86  
    87  	if len(r.destinationAddressItems) > 0 && !metadata.DestinationAddressMatch {
    88  		metadata.DidMatch = true
    89  		for _, item := range r.destinationAddressItems {
    90  			if item.Match(metadata) {
    91  				metadata.DestinationAddressMatch = true
    92  				break
    93  			}
    94  		}
    95  	}
    96  
    97  	if !metadata.IgnoreDestinationIPCIDRMatch && len(r.destinationIPCIDRItems) > 0 && !metadata.DestinationAddressMatch {
    98  		metadata.DidMatch = true
    99  		for _, item := range r.destinationIPCIDRItems {
   100  			if item.Match(metadata) {
   101  				metadata.DestinationAddressMatch = true
   102  				break
   103  			}
   104  		}
   105  	}
   106  
   107  	if len(r.destinationPortItems) > 0 && !metadata.DestinationPortMatch {
   108  		metadata.DidMatch = true
   109  		for _, item := range r.destinationPortItems {
   110  			if item.Match(metadata) {
   111  				metadata.DestinationPortMatch = true
   112  				break
   113  			}
   114  		}
   115  	}
   116  
   117  	for _, item := range r.items {
   118  		if _, isRuleSet := item.(*RuleSetItem); !isRuleSet {
   119  			metadata.DidMatch = true
   120  		}
   121  		if !item.Match(metadata) {
   122  			return r.invert
   123  		}
   124  	}
   125  
   126  	if len(r.sourceAddressItems) > 0 && !metadata.SourceAddressMatch {
   127  		return r.invert
   128  	}
   129  
   130  	if len(r.sourcePortItems) > 0 && !metadata.SourcePortMatch {
   131  		return r.invert
   132  	}
   133  
   134  	if ((!metadata.IgnoreDestinationIPCIDRMatch && len(r.destinationIPCIDRItems) > 0) || len(r.destinationAddressItems) > 0) && !metadata.DestinationAddressMatch {
   135  		return r.invert
   136  	}
   137  
   138  	if len(r.destinationPortItems) > 0 && !metadata.DestinationPortMatch {
   139  		return r.invert
   140  	}
   141  
   142  	if !metadata.DidMatch {
   143  		return true
   144  	}
   145  
   146  	return !r.invert
   147  }
   148  
   149  func (r *abstractDefaultRule) Outbound() string {
   150  	return r.outbound
   151  }
   152  
   153  func (r *abstractDefaultRule) String() string {
   154  	if !r.invert {
   155  		return strings.Join(F.MapToString(r.allItems), " ")
   156  	} else {
   157  		return "!(" + strings.Join(F.MapToString(r.allItems), " ") + ")"
   158  	}
   159  }
   160  
   161  type abstractLogicalRule struct {
   162  	rules    []adapter.HeadlessRule
   163  	mode     string
   164  	invert   bool
   165  	outbound string
   166  }
   167  
   168  func (r *abstractLogicalRule) Type() string {
   169  	return C.RuleTypeLogical
   170  }
   171  
   172  func (r *abstractLogicalRule) UpdateGeosite() error {
   173  	for _, rule := range common.FilterIsInstance(r.rules, func(it adapter.HeadlessRule) (adapter.Rule, bool) {
   174  		rule, loaded := it.(adapter.Rule)
   175  		return rule, loaded
   176  	}) {
   177  		err := rule.UpdateGeosite()
   178  		if err != nil {
   179  			return err
   180  		}
   181  	}
   182  	return nil
   183  }
   184  
   185  func (r *abstractLogicalRule) Start() error {
   186  	for _, rule := range common.FilterIsInstance(r.rules, func(it adapter.HeadlessRule) (common.Starter, bool) {
   187  		rule, loaded := it.(common.Starter)
   188  		return rule, loaded
   189  	}) {
   190  		err := rule.Start()
   191  		if err != nil {
   192  			return err
   193  		}
   194  	}
   195  	return nil
   196  }
   197  
   198  func (r *abstractLogicalRule) Close() error {
   199  	for _, rule := range common.FilterIsInstance(r.rules, func(it adapter.HeadlessRule) (io.Closer, bool) {
   200  		rule, loaded := it.(io.Closer)
   201  		return rule, loaded
   202  	}) {
   203  		err := rule.Close()
   204  		if err != nil {
   205  			return err
   206  		}
   207  	}
   208  	return nil
   209  }
   210  
   211  func (r *abstractLogicalRule) Match(metadata *adapter.InboundContext) bool {
   212  	if r.mode == C.LogicalTypeAnd {
   213  		return common.All(r.rules, func(it adapter.HeadlessRule) bool {
   214  			metadata.ResetRuleCache()
   215  			return it.Match(metadata)
   216  		}) != r.invert
   217  	} else {
   218  		return common.Any(r.rules, func(it adapter.HeadlessRule) bool {
   219  			metadata.ResetRuleCache()
   220  			return it.Match(metadata)
   221  		}) != r.invert
   222  	}
   223  }
   224  
   225  func (r *abstractLogicalRule) Outbound() string {
   226  	return r.outbound
   227  }
   228  
   229  func (r *abstractLogicalRule) String() string {
   230  	var op string
   231  	switch r.mode {
   232  	case C.LogicalTypeAnd:
   233  		op = "&&"
   234  	case C.LogicalTypeOr:
   235  		op = "||"
   236  	}
   237  	if !r.invert {
   238  		return strings.Join(F.MapToString(r.rules), " "+op+" ")
   239  	} else {
   240  		return "!(" + strings.Join(F.MapToString(r.rules), " "+op+" ") + ")"
   241  	}
   242  }