Add pre-match support for auto redirect

This commit is contained in:
世界
2025-12-26 15:52:28 +08:00
parent a34868468f
commit 78b4eac974
17 changed files with 354 additions and 11 deletions
+26 -1
View File
@@ -113,6 +113,17 @@ func (r *Router) routeConnection(ctx context.Context, conn net.Conn, metadata ad
buf.ReleaseMulti(buffers)
return E.New("TCP is not supported by outbound: ", selectedOutbound.Tag())
}
case *R.RuleActionBypass:
var loaded bool
selectedOutbound, loaded = r.outbound.Outbound(action.Outbound)
if !loaded {
buf.ReleaseMulti(buffers)
return E.New("outbound not found: ", action.Outbound)
}
if !common.Contains(selectedOutbound.Network(), N.NetworkTCP) {
buf.ReleaseMulti(buffers)
return E.New("TCP is not supported by outbound: ", selectedOutbound.Tag())
}
case *R.RuleActionReject:
buf.ReleaseMulti(buffers)
if action.Method == C.RuleActionRejectMethodReply {
@@ -231,6 +242,17 @@ func (r *Router) routePacketConnection(ctx context.Context, conn N.PacketConn, m
N.ReleaseMultiPacketBuffer(packetBuffers)
return E.New("UDP is not supported by outbound: ", selectedOutbound.Tag())
}
case *R.RuleActionBypass:
var loaded bool
selectedOutbound, loaded = r.outbound.Outbound(action.Outbound)
if !loaded {
N.ReleaseMultiPacketBuffer(packetBuffers)
return E.New("outbound not found: ", action.Outbound)
}
if !common.Contains(selectedOutbound.Network(), N.NetworkUDP) {
N.ReleaseMultiPacketBuffer(packetBuffers)
return E.New("UDP is not supported by outbound: ", selectedOutbound.Tag())
}
case *R.RuleActionReject:
N.ReleaseMultiPacketBuffer(packetBuffers)
if action.Method == C.RuleActionRejectMethodReply {
@@ -287,6 +309,8 @@ func (r *Router) PreMatch(metadata adapter.InboundContext, routeContext tun.Dire
}
}
return nil, action.Error(context.Background())
case *R.RuleActionBypass:
return nil, &R.BypassedError{Cause: tun.ErrBypass}
case *R.RuleActionRoute:
if routeContext == nil {
return nil, nil
@@ -567,7 +591,8 @@ match:
actionType := currentRule.Action().Type()
if actionType == C.RuleActionTypeRoute ||
actionType == C.RuleActionTypeReject ||
actionType == C.RuleActionTypeHijackDNS {
actionType == C.RuleActionTypeHijackDNS ||
actionType == C.RuleActionTypeBypass {
selectedRule = currentRule
selectedRuleIndex = currentRuleIndex
break match
+48
View File
@@ -56,6 +56,21 @@ func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action opti
TLSFragmentFallbackDelay: time.Duration(action.RouteOptionsOptions.TLSFragmentFallbackDelay),
TLSRecordFragment: action.RouteOptionsOptions.TLSRecordFragment,
}, nil
case C.RuleActionTypeBypass:
return &RuleActionBypass{
Outbound: action.BypassOptions.Outbound,
RuleActionRouteOptions: RuleActionRouteOptions{
OverrideAddress: M.ParseSocksaddrHostPort(action.BypassOptions.OverrideAddress, 0),
OverridePort: action.BypassOptions.OverridePort,
NetworkStrategy: (*C.NetworkStrategy)(action.BypassOptions.NetworkStrategy),
FallbackDelay: time.Duration(action.BypassOptions.FallbackDelay),
UDPDisableDomainUnmapping: action.BypassOptions.UDPDisableDomainUnmapping,
UDPConnect: action.BypassOptions.UDPConnect,
TLSFragment: action.BypassOptions.TLSFragment,
TLSFragmentFallbackDelay: time.Duration(action.BypassOptions.TLSFragmentFallbackDelay),
TLSRecordFragment: action.BypassOptions.TLSRecordFragment,
},
}, nil
case C.RuleActionTypeDirect:
directDialer, err := dialer.New(ctx, option.DialerOptions(action.DirectOptions), false)
if err != nil {
@@ -158,6 +173,22 @@ func (r *RuleActionRoute) String() string {
return F.ToString("route(", strings.Join(descriptions, ","), ")")
}
type RuleActionBypass struct {
Outbound string
RuleActionRouteOptions
}
func (r *RuleActionBypass) Type() string {
return C.RuleActionTypeBypass
}
func (r *RuleActionBypass) String() string {
var descriptions []string
descriptions = append(descriptions, r.Outbound)
descriptions = append(descriptions, r.Descriptions()...)
return F.ToString("bypass(", strings.Join(descriptions, ","), ")")
}
type RuleActionRouteOptions struct {
OverrideAddress M.Socksaddr
OverridePort uint16
@@ -301,6 +332,23 @@ func IsRejected(err error) bool {
return errors.As(err, &rejected)
}
type BypassedError struct {
Cause error
}
func (b *BypassedError) Error() string {
return "bypassed"
}
func (b *BypassedError) Unwrap() error {
return b.Cause
}
func IsBypassed(err error) bool {
var bypassed *BypassedError
return errors.As(err, &bypassed)
}
type RuleActionReject struct {
Method string
NoDrop bool