sing-box/route/rule.go

138 lines
3.8 KiB
Go
Raw Normal View History

2022-07-02 14:07:50 +08:00
package route
import (
2022-07-02 22:55:10 +08:00
"strings"
2022-07-02 14:07:50 +08:00
"github.com/sagernet/sing-box/adapter"
2022-07-02 22:55:10 +08:00
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
2022-07-02 14:07:50 +08:00
"github.com/sagernet/sing-box/option"
2022-07-02 22:55:10 +08:00
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
2022-07-02 14:07:50 +08:00
F "github.com/sagernet/sing/common/format"
)
2022-07-02 22:55:10 +08:00
func NewRule(router adapter.Router, logger log.Logger, options option.Rule) (adapter.Rule, error) {
2022-07-03 01:57:04 +08:00
if common.IsEmptyByEquals(options) {
return nil, E.New("empty rule config")
}
2022-07-02 22:55:10 +08:00
switch options.Type {
case "", C.RuleTypeDefault:
2022-07-03 01:57:04 +08: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 22:55:10 +08:00
case C.RuleTypeLogical:
2022-07-03 01:57:04 +08: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 22:55:10 +08:00
default:
return nil, E.New("unknown rule type: ", options.Type)
}
}
2022-07-02 14:07:50 +08:00
var _ adapter.Rule = (*DefaultRule)(nil)
type DefaultRule struct {
index int
outbound string
items []RuleItem
}
type RuleItem interface {
2022-07-02 22:55:10 +08:00
Match(metadata *adapter.InboundContext) bool
2022-07-02 14:07:50 +08:00
String() string
}
2022-07-02 22:55:10 +08:00
func NewDefaultRule(router adapter.Router, logger log.Logger, options option.DefaultRule) (*DefaultRule, error) {
2022-07-02 14:07:50 +08:00
rule := &DefaultRule{
outbound: options.Outbound,
}
if len(options.Inbound) > 0 {
rule.items = append(rule.items, NewInboundRule(options.Inbound))
}
2022-07-02 22:55:10 +08: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 {
rule.items = append(rule.items, NewDomainItem(options.Domain, options.DomainSuffix))
}
if len(options.DomainKeyword) > 0 {
rule.items = append(rule.items, NewDomainKeywordItem(options.DomainKeyword))
}
2022-07-04 15:51:41 +08:00
if len(options.DomainRegex) > 0 {
item, err := NewDomainRegexItem(options.DomainRegex)
if err != nil {
return nil, E.Cause(err, "domain_regex")
}
rule.items = append(rule.items, item)
}
2022-07-02 22:55:10 +08:00
if len(options.SourceGeoIP) > 0 {
rule.items = append(rule.items, NewGeoIPItem(router, logger, true, options.SourceGeoIP))
}
if len(options.GeoIP) > 0 {
rule.items = append(rule.items, NewGeoIPItem(router, logger, false, options.GeoIP))
}
if len(options.SourceIPCIDR) > 0 {
item, err := NewIPCIDRItem(true, options.SourceIPCIDR)
if err != nil {
2022-07-04 15:51:41 +08:00
return nil, E.Cause(err, "source_ipcidr")
2022-07-02 22:55:10 +08:00
}
rule.items = append(rule.items, item)
}
if len(options.IPCIDR) > 0 {
item, err := NewIPCIDRItem(false, options.IPCIDR)
if err != nil {
2022-07-04 15:51:41 +08:00
return nil, E.Cause(err, "ipcidr")
2022-07-02 22:55:10 +08:00
}
rule.items = append(rule.items, item)
}
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 14:07:50 +08:00
}
2022-07-02 22:55:10 +08:00
func (r *DefaultRule) Match(metadata *adapter.InboundContext) bool {
2022-07-02 14:07:50 +08:00
for _, item := range r.items {
if item.Match(metadata) {
return true
}
}
return false
}
func (r *DefaultRule) Outbound() string {
return r.outbound
}
func (r *DefaultRule) String() string {
2022-07-02 22:55:10 +08:00
return strings.Join(common.Map(r.items, F.ToString0[RuleItem]), " ")
2022-07-02 14:07:50 +08:00
}