Add more spoof method

Signed-off-by: macronut <4027187+macronut@users.noreply.github.com>
This commit is contained in:
macronut
2026-04-29 19:24:49 +08:00
committed by 世界
parent 6e7301dd61
commit 3609cf660f
22 changed files with 360 additions and 1021 deletions
+12
View File
@@ -15,6 +15,7 @@ import (
"github.com/sagernet/sing-box/common/dialer"
"github.com/sagernet/sing-box/common/sniff"
"github.com/sagernet/sing-box/common/tlsfragment"
"github.com/sagernet/sing-box/common/tlsspoof"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
@@ -129,6 +130,17 @@ func (m *ConnectionManager) NewConnection(ctx context.Context, this N.Dialer, co
if metadata.TLSFragment || metadata.TLSRecordFragment {
remoteConn = tf.NewConn(remoteConn, ctx, metadata.TLSFragment, metadata.TLSRecordFragment, metadata.TLSFragmentFallbackDelay)
}
if metadata.TLSSpoof != "" {
spoofConn, spoofErr := tlsspoof.NewConn(remoteConn, metadata.TLSSpoofMethod, metadata.TLSSpoof)
if spoofErr != nil {
spoofErr = E.Cause(spoofErr, "tls_spoof setup")
remoteConn.Close()
N.CloseOnHandshakeFailure(conn, onClose, spoofErr)
m.logger.ErrorContext(ctx, spoofErr)
return
}
remoteConn = spoofConn
}
serverFirst := sniff.Skip(&metadata)
var done atomic.Bool
if m.kickWriteHandshake(ctx, conn, remoteConn, serverFirst, false, &done, onClose) {
+8
View File
@@ -489,6 +489,10 @@ match:
routeOptions = &action.RuleActionRouteOptions
case *R.RuleActionRouteOptions:
routeOptions = action
case *R.RuleActionBypass:
if action.Outbound != "" {
routeOptions = &action.RuleActionRouteOptions
}
}
if routeOptions != nil {
// TODO: add nat
@@ -538,6 +542,10 @@ match:
if routeOptions.TLSRecordFragment {
metadata.TLSRecordFragment = true
}
if routeOptions.TLSSpoof != "" {
metadata.TLSSpoof = routeOptions.TLSSpoof
metadata.TLSSpoofMethod = routeOptions.TLSSpoofMethod
}
}
switch action := currentRule.Action().(type) {
case *R.RuleActionSniff:
+45 -36
View File
@@ -11,6 +11,7 @@ import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/dialer"
"github.com/sagernet/sing-box/common/sniff"
"github.com/sagernet/sing-box/common/tlsspoof"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-tun"
@@ -24,52 +25,54 @@ import (
"github.com/miekg/dns"
)
func newRuleActionRouteOptions(options option.RawRouteOptionsActionOptions) (RuleActionRouteOptions, error) {
spoof, spoofMethod, err := tlsspoof.ParseOptions(options.TLSSpoof, options.TLSSpoofMethod)
if err != nil {
return RuleActionRouteOptions{}, err
}
return RuleActionRouteOptions{
OverrideAddress: M.ParseSocksaddrHostPort(options.OverrideAddress, 0),
OverridePort: options.OverridePort,
NetworkStrategy: (*C.NetworkStrategy)(options.NetworkStrategy),
FallbackDelay: time.Duration(options.FallbackDelay),
UDPDisableDomainUnmapping: options.UDPDisableDomainUnmapping,
UDPConnect: options.UDPConnect,
UDPTimeout: time.Duration(options.UDPTimeout),
TLSFragment: options.TLSFragment,
TLSFragmentFallbackDelay: time.Duration(options.TLSFragmentFallbackDelay),
TLSRecordFragment: options.TLSRecordFragment,
TLSSpoof: spoof,
TLSSpoofMethod: spoofMethod,
}, nil
}
func NewRuleAction(ctx context.Context, logger logger.ContextLogger, action option.RuleAction) (adapter.RuleAction, error) {
switch action.Action {
case "":
return nil, nil
case C.RuleActionTypeRoute:
routeOptions, err := newRuleActionRouteOptions(action.RouteOptions.RawRouteOptionsActionOptions)
if err != nil {
return nil, err
}
return &RuleActionRoute{
Outbound: action.RouteOptions.Outbound,
RuleActionRouteOptions: RuleActionRouteOptions{
OverrideAddress: M.ParseSocksaddrHostPort(action.RouteOptions.OverrideAddress, 0),
OverridePort: action.RouteOptions.OverridePort,
NetworkStrategy: (*C.NetworkStrategy)(action.RouteOptions.NetworkStrategy),
FallbackDelay: time.Duration(action.RouteOptions.FallbackDelay),
UDPDisableDomainUnmapping: action.RouteOptions.UDPDisableDomainUnmapping,
UDPConnect: action.RouteOptions.UDPConnect,
TLSFragment: action.RouteOptions.TLSFragment,
TLSFragmentFallbackDelay: time.Duration(action.RouteOptions.TLSFragmentFallbackDelay),
TLSRecordFragment: action.RouteOptions.TLSRecordFragment,
},
Outbound: action.RouteOptions.Outbound,
RuleActionRouteOptions: routeOptions,
}, nil
case C.RuleActionTypeRouteOptions:
return &RuleActionRouteOptions{
OverrideAddress: M.ParseSocksaddrHostPort(action.RouteOptionsOptions.OverrideAddress, 0),
OverridePort: action.RouteOptionsOptions.OverridePort,
NetworkStrategy: (*C.NetworkStrategy)(action.RouteOptionsOptions.NetworkStrategy),
FallbackDelay: time.Duration(action.RouteOptionsOptions.FallbackDelay),
UDPDisableDomainUnmapping: action.RouteOptionsOptions.UDPDisableDomainUnmapping,
UDPConnect: action.RouteOptionsOptions.UDPConnect,
UDPTimeout: time.Duration(action.RouteOptionsOptions.UDPTimeout),
TLSFragment: action.RouteOptionsOptions.TLSFragment,
TLSFragmentFallbackDelay: time.Duration(action.RouteOptionsOptions.TLSFragmentFallbackDelay),
TLSRecordFragment: action.RouteOptionsOptions.TLSRecordFragment,
}, nil
routeOptions, err := newRuleActionRouteOptions(option.RawRouteOptionsActionOptions(action.RouteOptionsOptions))
if err != nil {
return nil, err
}
return &routeOptions, nil
case C.RuleActionTypeBypass:
routeOptions, err := newRuleActionRouteOptions(action.BypassOptions.RawRouteOptionsActionOptions)
if err != nil {
return nil, err
}
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,
},
Outbound: action.BypassOptions.Outbound,
RuleActionRouteOptions: routeOptions,
}, nil
case C.RuleActionTypeDirect:
directDialer, err := dialer.New(ctx, option.DialerOptions(action.DirectOptions), false)
@@ -225,6 +228,8 @@ type RuleActionRouteOptions struct {
TLSFragment bool
TLSFragmentFallbackDelay time.Duration
TLSRecordFragment bool
TLSSpoof string
TLSSpoofMethod tlsspoof.Method
}
func (r *RuleActionRouteOptions) Type() string {
@@ -273,6 +278,10 @@ func (r *RuleActionRouteOptions) Descriptions() []string {
if r.TLSRecordFragment {
descriptions = append(descriptions, "tls-record-fragment")
}
if r.TLSSpoof != "" {
descriptions = append(descriptions, F.ToString("tls-spoof=", r.TLSSpoof))
descriptions = append(descriptions, F.ToString("tls-spoof-method=", r.TLSSpoofMethod.String()))
}
return descriptions
}