Improve rule actions

This commit is contained in:
世界
2024-11-06 17:30:40 +08:00
parent 607f315f91
commit 2156b40f3a
10 changed files with 414 additions and 138 deletions

View File

@@ -5,9 +5,11 @@ import (
"net/netip"
"strings"
"sync"
"syscall"
"time"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/dialer"
"github.com/sagernet/sing-box/common/sniff"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
@@ -17,19 +19,42 @@ import (
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/logger"
"golang.org/x/sys/unix"
N "github.com/sagernet/sing/common/network"
)
func NewRuleAction(logger logger.ContextLogger, action option.RuleAction) (adapter.RuleAction, error) {
func NewRuleAction(router adapter.Router, logger logger.ContextLogger, action option.RuleAction) (adapter.RuleAction, error) {
switch action.Action {
case "":
return nil, nil
case C.RuleActionTypeRoute:
return &RuleActionRoute{
Outbound: action.RouteOptions.Outbound,
UDPDisableDomainUnmapping: action.RouteOptions.UDPDisableDomainUnmapping,
Outbound: action.RouteOptions.Outbound,
}, nil
case C.RuleActionTypeRouteOptions:
return &RuleActionRouteOptions{
UDPDisableDomainUnmapping: action.RouteOptionsOptions.UDPDisableDomainUnmapping,
UDPConnect: action.RouteOptionsOptions.UDPConnect,
}, nil
case C.RuleActionTypeDirect:
directDialer, err := dialer.New(router, option.DialerOptions(action.DirectOptions))
if err != nil {
return nil, err
}
var description string
descriptions := action.DirectOptions.Descriptions()
switch len(descriptions) {
case 0:
case 1:
description = F.ToString("(", descriptions[0], ")")
case 2:
description = F.ToString("(", descriptions[0], ",", descriptions[1], ")")
default:
description = F.ToString("(", descriptions[0], ",", descriptions[1], ",...)")
}
return &RuleActionDirect{
Dialer: directDialer,
description: description,
}, nil
case C.RuleActionTypeReturn:
return &RuleActionReturn{}, nil
case C.RuleActionTypeReject:
return &RuleActionReject{
Method: action.RejectOptions.Method,
@@ -56,6 +81,8 @@ func NewRuleAction(logger logger.ContextLogger, action option.RuleAction) (adapt
func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction) adapter.RuleAction {
switch action.Action {
case "":
return nil
case C.RuleActionTypeRoute:
return &RuleActionDNSRoute{
Server: action.RouteOptions.Server,
@@ -63,8 +90,12 @@ func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction)
RewriteTTL: action.RouteOptions.RewriteTTL,
ClientSubnet: action.RouteOptions.ClientSubnet.Build(),
}
case C.RuleActionTypeReturn:
return &RuleActionReturn{}
case C.RuleActionTypeRouteOptions:
return &RuleActionDNSRouteOptions{
DisableCache: action.RouteOptionsOptions.DisableCache,
RewriteTTL: action.RouteOptionsOptions.RewriteTTL,
ClientSubnet: action.RouteOptionsOptions.ClientSubnet.Build(),
}
case C.RuleActionTypeReject:
return &RuleActionReject{
Method: action.RejectOptions.Method,
@@ -77,8 +108,7 @@ func NewDNSRuleAction(logger logger.ContextLogger, action option.DNSRuleAction)
}
type RuleActionRoute struct {
Outbound string
UDPDisableDomainUnmapping bool
Outbound string
}
func (r *RuleActionRoute) Type() string {
@@ -89,6 +119,26 @@ func (r *RuleActionRoute) String() string {
return F.ToString("route(", r.Outbound, ")")
}
type RuleActionRouteOptions struct {
UDPDisableDomainUnmapping bool
UDPConnect bool
}
func (r *RuleActionRouteOptions) Type() string {
return C.RuleActionTypeRouteOptions
}
func (r *RuleActionRouteOptions) String() string {
var descriptions []string
if r.UDPDisableDomainUnmapping {
descriptions = append(descriptions, "udp-disable-domain-unmapping")
}
if r.UDPConnect {
descriptions = append(descriptions, "udp-connect")
}
return F.ToString("route-options(", strings.Join(descriptions, ","), ")")
}
type RuleActionDNSRoute struct {
Server string
DisableCache bool
@@ -104,14 +154,41 @@ func (r *RuleActionDNSRoute) String() string {
return F.ToString("route(", r.Server, ")")
}
type RuleActionReturn struct{}
func (r *RuleActionReturn) Type() string {
return C.RuleActionTypeReturn
type RuleActionDNSRouteOptions struct {
DisableCache bool
RewriteTTL *uint32
ClientSubnet netip.Prefix
}
func (r *RuleActionReturn) String() string {
return "return"
func (r *RuleActionDNSRouteOptions) Type() string {
return C.RuleActionTypeRouteOptions
}
func (r *RuleActionDNSRouteOptions) String() string {
var descriptions []string
if r.DisableCache {
descriptions = append(descriptions, "disable-cache")
}
if r.RewriteTTL != nil {
descriptions = append(descriptions, F.ToString("rewrite-ttl(", *r.RewriteTTL, ")"))
}
if r.ClientSubnet.IsValid() {
descriptions = append(descriptions, F.ToString("client-subnet(", r.ClientSubnet, ")"))
}
return F.ToString("route-options(", strings.Join(descriptions, ","), ")")
}
type RuleActionDirect struct {
Dialer N.Dialer
description string
}
func (r *RuleActionDirect) Type() string {
return C.RuleActionTypeDirect
}
func (r *RuleActionDirect) String() string {
return "direct" + r.description
}
type RuleActionReject struct {
@@ -137,7 +214,7 @@ func (r *RuleActionReject) Error(ctx context.Context) error {
var returnErr error
switch r.Method {
case C.RuleActionRejectMethodDefault:
returnErr = unix.ECONNREFUSED
returnErr = syscall.ECONNREFUSED
case C.RuleActionRejectMethodDrop:
return tun.ErrDrop
default:

View File

@@ -52,7 +52,7 @@ type RuleItem interface {
}
func NewDefaultRule(ctx context.Context, router adapter.Router, logger log.ContextLogger, options option.DefaultRule) (*DefaultRule, error) {
action, err := NewRuleAction(logger, options.RuleAction)
action, err := NewRuleAction(router, logger, options.RuleAction)
if err != nil {
return nil, E.Cause(err, "action")
}
@@ -254,7 +254,7 @@ type LogicalRule struct {
}
func NewLogicalRule(ctx context.Context, router adapter.Router, logger log.ContextLogger, options option.LogicalRule) (*LogicalRule, error) {
action, err := NewRuleAction(logger, options.RuleAction)
action, err := NewRuleAction(router, logger, options.RuleAction)
if err != nil {
return nil, E.Cause(err, "action")
}