sing-box/route/rule.go

166 lines
4.6 KiB
Go
Raw Normal View History

2022-07-02 06:07:50 +00:00
package route
import (
2022-07-02 14:55:10 +00:00
"strings"
2022-07-02 06:07:50 +00:00
"github.com/sagernet/sing-box/adapter"
2022-07-02 14:55:10 +00:00
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
2022-07-02 06:07:50 +00:00
"github.com/sagernet/sing-box/option"
2022-07-02 14:55:10 +00:00
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
2022-07-02 06:07:50 +00:00
F "github.com/sagernet/sing/common/format"
)
2022-07-02 14:55:10 +00:00
func NewRule(router adapter.Router, logger log.Logger, options option.Rule) (adapter.Rule, error) {
2022-07-02 17:57:04 +00:00
if common.IsEmptyByEquals(options) {
return nil, E.New("empty rule config")
}
2022-07-02 14:55:10 +00:00
switch options.Type {
case "", C.RuleTypeDefault:
2022-07-02 17:57:04 +00:00
if !options.DefaultOptions.IsValid() {
return nil, E.New("missing conditions")
}
if options.DefaultOptions.Outbound == "" {
return nil, E.New("missing outbound field")
}
return NewDefaultRule(router, logger, options.DefaultOptions)
2022-07-02 14:55:10 +00:00
case C.RuleTypeLogical:
2022-07-02 17:57:04 +00:00
if !options.LogicalOptions.IsValid() {
return nil, E.New("missing conditions")
}
if options.LogicalOptions.Outbound == "" {
return nil, E.New("missing outbound field")
}
return NewLogicalRule(router, logger, options.LogicalOptions)
2022-07-02 14:55:10 +00:00
default:
return nil, E.New("unknown rule type: ", options.Type)
}
}
2022-07-02 06:07:50 +00:00
var _ adapter.Rule = (*DefaultRule)(nil)
type DefaultRule struct {
2022-07-04 11:34:45 +00:00
items []RuleItem
sourceAddressItems []RuleItem
destinationAddressItems []RuleItem
outbound string
2022-07-02 06:07:50 +00:00
}
type RuleItem interface {
2022-07-02 14:55:10 +00:00
Match(metadata *adapter.InboundContext) bool
2022-07-02 06:07:50 +00:00
String() string
}
2022-07-02 14:55:10 +00:00
func NewDefaultRule(router adapter.Router, logger log.Logger, options option.DefaultRule) (*DefaultRule, error) {
2022-07-02 06:07:50 +00:00
rule := &DefaultRule{
outbound: options.Outbound,
}
if len(options.Inbound) > 0 {
rule.items = append(rule.items, NewInboundRule(options.Inbound))
}
2022-07-02 14:55:10 +00:00
if options.IPVersion > 0 {
switch options.IPVersion {
case 4, 6:
rule.items = append(rule.items, NewIPVersionItem(options.IPVersion == 6))
default:
return nil, E.New("invalid ip version: ", options.IPVersion)
}
}
if options.Network != "" {
switch options.Network {
case C.NetworkTCP, C.NetworkUDP:
rule.items = append(rule.items, NewNetworkItem(options.Network))
default:
return nil, E.New("invalid network: ", options.Network)
}
}
if len(options.Protocol) > 0 {
rule.items = append(rule.items, NewProtocolItem(options.Protocol))
}
if len(options.Domain) > 0 || len(options.DomainSuffix) > 0 {
2022-07-04 11:34:45 +00:00
rule.destinationAddressItems = append(rule.destinationAddressItems, NewDomainItem(options.Domain, options.DomainSuffix))
2022-07-02 14:55:10 +00:00
}
if len(options.DomainKeyword) > 0 {
2022-07-04 11:34:45 +00:00
rule.destinationAddressItems = append(rule.destinationAddressItems, NewDomainKeywordItem(options.DomainKeyword))
2022-07-02 14:55:10 +00:00
}
2022-07-04 07:51:41 +00:00
if len(options.DomainRegex) > 0 {
item, err := NewDomainRegexItem(options.DomainRegex)
if err != nil {
return nil, E.Cause(err, "domain_regex")
}
2022-07-04 11:34:45 +00:00
rule.destinationAddressItems = append(rule.destinationAddressItems, item)
2022-07-04 07:51:41 +00:00
}
2022-07-02 14:55:10 +00:00
if len(options.SourceGeoIP) > 0 {
2022-07-04 11:34:45 +00:00
rule.sourceAddressItems = append(rule.sourceAddressItems, NewGeoIPItem(router, logger, true, options.SourceGeoIP))
2022-07-02 14:55:10 +00:00
}
if len(options.GeoIP) > 0 {
2022-07-04 11:34:45 +00:00
rule.destinationAddressItems = append(rule.destinationAddressItems, NewGeoIPItem(router, logger, false, options.GeoIP))
2022-07-02 14:55:10 +00:00
}
if len(options.SourceIPCIDR) > 0 {
item, err := NewIPCIDRItem(true, options.SourceIPCIDR)
if err != nil {
2022-07-04 07:51:41 +00:00
return nil, E.Cause(err, "source_ipcidr")
2022-07-02 14:55:10 +00:00
}
2022-07-04 11:34:45 +00:00
rule.sourceAddressItems = append(rule.sourceAddressItems, item)
2022-07-02 14:55:10 +00:00
}
if len(options.IPCIDR) > 0 {
item, err := NewIPCIDRItem(false, options.IPCIDR)
if err != nil {
2022-07-04 07:51:41 +00:00
return nil, E.Cause(err, "ipcidr")
2022-07-02 14:55:10 +00:00
}
2022-07-04 11:34:45 +00:00
rule.destinationAddressItems = append(rule.destinationAddressItems, item)
2022-07-02 14:55:10 +00:00
}
if len(options.SourcePort) > 0 {
rule.items = append(rule.items, NewPortItem(true, options.SourcePort))
}
if len(options.Port) > 0 {
rule.items = append(rule.items, NewPortItem(false, options.Port))
}
return rule, nil
2022-07-02 06:07:50 +00:00
}
2022-07-02 14:55:10 +00:00
func (r *DefaultRule) Match(metadata *adapter.InboundContext) bool {
2022-07-02 06:07:50 +00:00
for _, item := range r.items {
2022-07-04 11:34:45 +00:00
if !item.Match(metadata) {
return false
2022-07-02 06:07:50 +00:00
}
}
2022-07-04 11:34:45 +00:00
if len(r.sourceAddressItems) > 0 {
var sourceAddressMatch bool
for _, item := range r.sourceAddressItems {
if item.Match(metadata) {
sourceAddressMatch = true
break
}
}
if !sourceAddressMatch {
return false
}
}
if len(r.destinationAddressItems) > 0 {
var destinationAddressMatch bool
for _, item := range r.destinationAddressItems {
if item.Match(metadata) {
destinationAddressMatch = true
break
}
}
if !destinationAddressMatch {
return false
}
}
return true
2022-07-02 06:07:50 +00:00
}
func (r *DefaultRule) Outbound() string {
return r.outbound
}
func (r *DefaultRule) String() string {
2022-07-02 14:55:10 +00:00
return strings.Join(common.Map(r.items, F.ToString0[RuleItem]), " ")
2022-07-02 06:07:50 +00:00
}